0

In Unity C# script I have a singleton game controller object in which the game variables are stored but I am getting odd behaviour when accessing them in a member function. It prints the initialized value, not the current one. In the update function however it prints the correct value each frame. I summarized the class below. The controller class has a static reference to itself. If you need to know additional details you can ask. I am new to C# and Unity so I might be lacking some obvious answer.

Thanks

public class controller : MonoBehaviour {

    public int[] star = new int[64];

    void Start(){ /* calls another function to set 0 for each star index */ }

    void Update(){  // during gameplay star[0] gets a value of 1
        print(star[0]);  // prints correct value which is 1
    }

    public void checkValue(){
        print(star[0]); // prints 0 incorrectly which should be 1     
    }


}
11
  • I located the problem but I dont know how to solve it. checkValue function runs when a button is pressed and it returns the right value if it was called from the update. No idea whats causing it Commented Jul 3, 2016 at 8:02
  • Start should be a no-op since the array is initialized to zero anyways. Otherwise something not visible in this snippet of code happens. Commented Jul 3, 2016 at 9:20
  • Is it the same instance of controller in all cases. Each instance has its own field ("class variable") when you use a non-static member star. Commented Jul 3, 2016 at 9:26
  • @JeppeStigNielsen yes it is the same instance that was first created. Please read my comment in the other answer I need to know how that solves it. Commented Jul 3, 2016 at 9:44
  • Just to make sure: you are speaking of a singleton, but this code is not implementing that pattern. Do you have it somewhere else? A singleton in unity is rather easy to implement. Commented Jul 3, 2016 at 11:12

3 Answers 3

1

I've set up a little example. I created a button and an empty gameobject GameController. I added this code to the GameController:

using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour {

    public static GameController instance;

    [System.NonSerialized] public int[] star = new int[64];

    private void Awake()
    {
        if(instance == null)
            instance = this;
        else if(instance != this)
            Destroy(gameObject);

        DontDestroyOnLoad(gameObject);
    }

    private void Start()
    {
        StartCoroutine(SetAllTo(1));
    }

    // for simulating some changes during the game
    private IEnumerator SetAllTo(int value)
    {
        yield return new WaitForSeconds(2.0f);

        for(int i = 0; i < star.Length; i++)
            star[i] = value;

        Debug.Log("Setting done");
    }

    public void PrintFirst()
    {
        Debug.Log(star[0]);
    }
}

Now I added an OnClick event to the button, dragged the GameController gameobject into the slot and picked PrintFirst.

I start the game and click the button once before the Coroutine log and once after and the console gives the following:

0
Setting Done
1

Edit:
The gameobject for the OnClick event must be in the scene, it can't be a prefab in the assets folder.

Sign up to request clarification or add additional context in comments.

9 Comments

Thats interesting. Did you drag the GameController that was present in the scene into the OnClick event ? That works for me too but it doesnt work if I drag a prefab.
Oh, yes, from the scene. If by dragging a prefab you actually mean dragging it from the assets folder: That will never work. Prefabs are not part of the game, only blueprints on your harddrive. You can only reference stuff that is in the scene (hierarchy) or somehow connected to something in the scene (like a non-MonoBehaviour script in a MonoBehaviour script created with new).
Ok I got it but I can run the function of the prefab, for example it prints a string. It returns the default value of the class variables it seems. But how does it call them without calling a constructor? I put a print in constructor and it didnt print when the button was clicked. Thanks a lot for your help by the way!
Classes that derive from MonoBehaviour don't have a constructor (and you can't use new to create a reference to such a class). I can't really tell, what it does when you try it on a prefab.
Hi Gunnar, to avoid me entering an answer I edited yours to show that "star" should absolutely be [System.NonSerialized] public
|
0

It seems that's the call to the start function may also occurs in your external calls before the call for ckeckValue

Try debugging by putting breakpoint in each of these functions and you can understand what is going on.

2 Comments

The start function runs once in the beginning of the game and not again. checkValue function runs when a button is pressed. If that were the case update function wouldnt be returning the correct one after the button was clicked I guess.
Add a public property and use the field star and also make field private. Add breakpoint in the setter to observe whenever value is set and use code map to view the caller
0

The start function runs once in the beginning of the game and not again.

For that you have pattern - Singleton

The second thing why to call external function to initialize class member? do it in your default contractor.

- C# default constractor already initialize 0 in int[].

if you still what to run Start from other scope in your code make it public (c# makes variable/methods as private by default)

7 Comments

Thanks for your help. I'm still learning the design. When I debug with print I see the Start runs once during the scene.The reason I call another function in Start is that it has to save and load based on the state of the game and they are class functions and not external ones.
I located what the problem is though. The function that gives wrong results is called by a button in Unity. Somehow when the button is pressed it does not look for the controller object that is present in the scene and uses the class itself which has the default value of 0 for its star variable. But more interestingly it doesnt trigger its constructor in the process. If I told the function to specifically look for the instance of that class that is present in the scene and use its variables, then boom it works.
Hi Leon. NOte that this is a UNITY3D project - there are NO singletons.
A Singleton just way to creates an instance of your class and prevents new instances from being created more than one time it's design pattern not technology. (design pattern - is a general repeatable solution to a commonly occurring problem in software design.)
Hi Leon. I don't know how clear I can be, this is for Unity3D, the game engine. It is an ECS system, it does not have singletons. (How could you make a "singleton component for a GameObject". What would that even mean?) ECS systems have utterly no connection to OO.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.