Why do my bool trigger differently depending on from where I init it

I have a strange problem (at least for me) that I do not understand with my bool “firstClick”. I know I have it declared and used in only one single script. Part of my debugging was to rename it.

The problem is that it is triggered differently if I start the script from the actual script or from another class despite the fact that both start sequences include init it as true.

When I initiate from GameManager class I get the following result (print):

InitializeGame - firstClick: True 
BTN_Selected - firstClick: True <<<<
A) C
BTN_Selected - firstClick: False
pnl_MenuNoAccess.SetActive(true)
B) A
pnl_MenuNoAccess.SetActive(false)

…which is exactly as I want it.

However, when I start the initiation from SetupMatch I get a different result:

InitializeGame - firstClick: True 
BTN_Selected - firstClick: False <<<<
pnl_MenuNoAccess.SetActive(true)
B) A
BTN_Selected - firstClick: True
A) C
pnl_MenuNoAccess.SetActive(false)

I just do not understand why firstClick becomes false as it is init as true in the GameManager Start function. The SetupMatch class inherit from GameManager, which is the main class. I guess it must have something to do with that but I do not understand why.

Here is the “main” script:
public class GameManager : MonoBehaviour

private bool firstClick;
private void Start()
    {
        Utilities._ui = FindObjectOfType(typeof(UI_Alloc_and_More)) as UI_Alloc_and_More;

        _sm = FindObjectOfType(typeof(SetupMatch)) as SetupMatch;

        Utilities.AllocateUI();
        Utilities.SetColorScheme();
        Utilities.AssigningValuesToButtons(0);
        InitializeGame(); <<<<<<<<<<<<
    }
public void InitializeGame()
    {
        Utilities.AssigningValuesToButtons(1);
        Utilities.AssignButtons(20); // Between 4 - 20

        firstClick = true;
        print("firstClick: " + firstClick);
        isMovingCardsToTrashCan = false;
        moveSpeed = 4;

        points = 0;
        Utilities.txt_Points.text = points.ToString();

     }

Here is the buttons:

public void BTN_Selected(int _btnNr)
    {
        print("BTN_Selected - firstClick: " + firstClick);
        if (firstClick)
        {
            int_Btn_A_Nr = _btnNr;
            btn_A = btn_List[int_Btn_A_Nr].name;
            firstClick = false;
            print("A) " + btn_A);

            // Flip from backside to front
            btn_Temp = btn_List[int_Btn_A_Nr];
            btn_Temp.image.sprite = Utilities._ui.spr_myFront;
            btn_Temp.image.color = Utilities.colorCardFrontUI;
            btn_Temp.GetComponentInChildren<Text>().color = Utilities.colorCardFrontText;
            btn_Temp.GetComponentInChildren<Text>().text = btn_Temp.name;
        }
        else
        {
            // Inhibit access during the card move-out
            pnl_MenuNoAccess.SetActive(true);
            print("pnl_MenuNoAccess.SetActive(true)");

            int_Btn_B_Nr = _btnNr;
            btn_B = btn_List[int_Btn_B_Nr].name;
            firstClick = true;
            print("B) " + btn_B);

            // Flip from backside to front
            btn_Temp = btn_List[int_Btn_B_Nr];
            btn_Temp.image.sprite = Utilities._ui.spr_myFront;
            btn_Temp.image.color = Utilities.colorCardFrontUI;
            btn_Temp.GetComponentInChildren<Text>().color = Utilities.colorCardFrontText;
            btn_Temp.GetComponentInChildren<Text>().text = btn_Temp.name;


            if (btn_A == btn_B)
            {
                print("btn_A == btn_B");
                // This is a hit: Wait a few seconds and then add points and move the cards out the scene and destroy them.
                points++;
                Utilities.txt_Points.text = points.ToString();

                // Move card to trashcan
           
                Invoke(nameof(MoveHitCardsToCardTrashCan), 1.5f);
            }
            else
            {
                Invoke(nameof(FlipTheCard), 1.5f);

                // Enable access during the card move-out
            }

            btn_A = "";
            btn_B = "";
        }
    }

Another class:
public class SetupMatch : GameManager

public void BTN_PlayGame()
    {
         InitializeGame();
    }

Well we don’t really have the full picture here. However in 99% of such cases you usually access the wrong object. Keep in mind that prefabs are also valid useable objects, but they don’t live in the scene. They don’t get any callbacks from Untiy but you can still call methods on them.

I generally avoid the “print” method since it’s an instance method of MonoBehaviour and just a wrapper of Debug.Log with less options. When you use Debug.Log you can pass a second “context” object. This context object will be pinged / highlighted in Untiy when you click on the log message in the console. This makes it a lot easier to figure out what objects you’re dealing with. So try adding gameObject as second parameter and see which objects you’re calling your methods on.

If that doesn’t help a neat trick to figure out who and when a variable is changed, you can temporarily replace the variable with a property and add a Debug.Log to the setter. The log message gives you a full stacktrace which often helpt to figure out who’s messing with your variable.

Finally you seem to toggle your firstClick variable whenever you call the “BTN_Selected” method. Is that intentional? is this variable to track to two step process somehow? If this is just about selecting a card (as it seems) what’s the exact usecase for that variable? When you can only select one card, you usually have a variable that holds the index / object reference of the thing you have selected. When nothing is selected the variable would be null or -1 or something like that to indicate no selection. Though as I said, we only have a very limited overview of your setup.

1 Like

After a lot of tests I did solve this problem but not the way I wanted.

Solution is that I changed the “public class SetupMatch : GameManager” to “public class SetupMatch : MonoBehaviour” and reference all GameManager fields and classes need to be accessed.

I still do not understand why the fields do not keep their assigned values, set in “InitializeGame()”, when starting that function from the inherited class in another script? …only when I start “InitializeGame()” from the same script?

Can you share the results of the Debug.Log suggestions?

1 Like

I get the feeling that you have the completely wrong idea about inheritance here. It doesn’t seem to make much sense to derive your “SetupMatch” class from the “GameManager” class. You do understand that a class is just like the DNA of a living being. In biology we don’t really clone people, however multiple instances of the same class / DNA would be several clones. Though each clone is of course a seperate person. If one gets a haircut, the other won’t be affected by this.

Inheritance goes even a step further. You have inherited your DNA from your parents and maybe got some random mutations / changes applied to your DNA. You may have inherited the hair from your father, but here the same logic applies. If your father gets a haircut, your own hair won’t get shorter. You are a seperate person / “instance”.

So my guess would be that you have an instance of your GameManager class and an instance of your SetupMatch class. Both have nothing to do with each other, at all. They are two seperate instances, each with its own set of variables and methods. If SetupMatch is derived from GameManager that just means it has inherited the “DNA” / the “blueprint” of the parent class. So it will have the same variables, but they are a seperate set of variables.

If that’s not your issue, you really should share more details about how your classes look like, which class has an instance in the scene and what method is called on which instance.