4
votes

First formal declarations: Programming Language: C# in Unity (MonoBehavior) My skill level: Kinda noob (less then half a year c# experience).

I am making a block breaker game (Arkanoid) and are making an acheivement system. The game is one-shot, all is deleted when you close the web-build (no cache, no filesave, no serializable classes).

The Acheivement system contains of: "Acheivement" class: Lots of variables and a few methods to track progress. The script it attached to an empty GameObject with same name. Normal Class.

"AManager" class. The class that initializes a bunch of copies of the "Acheivement" class, give them individual values and add them to the dictionary mentioned below. Singelton Class.

"AcheivementDictionary" class: Only contains a private static dictionary and access methods. Also a singelton Class

The Problem:

The acheivements are made and added on "start" of the first scene. After they are added, I retrive the GameObjects and test if their tag works, and everything is fine. Then from my "levelManager" class I call the same method from next scene and get a message that the gameObjects are destroyed. If I test them, they also return null.

So... my real question is this:

How do I make my instansiated copies of Acheivement gameObjects to last through all scene changes in Unity?

Code references:

I do not think "acheivement" is the class that has any problem, if you need code from that class just holler.

"AManager"

public class Amanager : MonoBehaviour {

    public static Amanager acheivementManager = null;
public GameObject myAchObject;

void Awake () {
        if (acheivementManager != null) { 
        Destroy(gameObject);
        } else {
            acheivementManager = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
    }

void Start () {

    myAchObject.AddComponent<Acheivement>();


    initAcheivements ("completeLevelThree", "Level 3", "Complete level 3","Level", 3,5);
    initAcheivements ("completeLevelOne", "Level 1", "Complete level 1","Level", 1,5);
    }

private void initAcheivements(string inAch, string inNavn, string inHow, string inCountType, int goalVal, int Reward) {


            Vector3 loc = new Vector3 (0f, 0f,0f);
            GameObject testAch;
            testAch = Instantiate(myAchObject, loc, Quaternion.identity) as GameObject; 
            //testLives.SetActive (true);
            //testLives.gameObject.tag = "clone";

        testAch.GetComponent<Acheivement>().setName(inNavn);
        testAch.GetComponent<Acheivement>().setHowToGet(inHow);
        testAch.GetComponent<Acheivement>().setCountType(inCountType);
        testAch.GetComponent<Acheivement>().setGoalVal(goalVal);
        testAch.GetComponent<Acheivement>().setReward(Reward);
        testAch.tag = inCountType;
        Debug.Log ("InitiAch did run");
        AcheivementDictionary._Instance.achRegAdder(inNavn,testAch);
}

AcheivementDictionary code:

public class AcheivementDictionary : MonoBehaviour {
public static AcheivementDictionary _Instance;

    private static Dictionary<string,GameObject> AchReg = new Dictionary<string,GameObject>();

void Awake () {
        if (_Instance != null) { 
            Destroy(gameObject);
        } else {
            _Instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
    }
    }

    public void achRegAdder (string inName, GameObject theAch) {
    AchReg.Add(inName,theAch);
    Debug.Log ("achRegAdded did run");
    readThisString = inName;
    tryRead = true;
    }

    private void readIt() {
    Debug.Log ("readItRan"); 
    GameObject testShit; 
    AchReg.TryGetValue("Level 1",out testShit);
    Debug.Log("if it works level should stand there ---> " + testShit.tag);
    tryRead = false;
    }

    public void achRegReader () {
        readIt ();
    }

When ran, the following messages comes up in console:

initAch did run

achRegAdded did run

initAch did run

achRegAdded did run

readItRan

if it works level should stand there ---> Level

readitRan

MissingReferenceException: The object of type "GameObject" has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the obejct.

(this bug comes when trying to access tag of stored object and occurs in the following method call: Debug.Log("if it works level should stand there ---> " + testShit.tag);)

This is the codeline used to call the achRegReader when it fails (from another class): AcheivementDictionary._Instance.achRegReader();

Also: If I do count the number of objects in the dictionary, it does return 2. They are just destroyed, and I cannot really see why. There is no code anywhere in my program that destroy these.

My guesses are something like:

There are problems I do not understand with regards to placing static dictionaries in Singelton classes. The instansiated copies of Acheivements does not persist through scenes since they are not dontDestroyOnLoad even though both the classes that handle them are. Either way, I have not managed to isolate or solve the problem for the last 6 hours of struggle, please help!

1
Forgot to mention: I call the "read" message on all scene changes. I get no error messages in the start menu where the initialization is made, but I get the same error message on all scene loads after that.Allan Karseth
My guess is that something like scene change, destroys the gameobject. try adding testAch.transform.parent = transform; in initAcheivementsBizhan
That worked and I love you! Also... why did it work? And how do I give you credit for solving it, I don't see a "he solved the issue" button :DAllan Karseth
Your problem was that the instantiated objects were never told to DontDestroyOnLoad, only the object which instantiated them. You either had to call the DontDestroyOnLoad on the instantiated objects or make them children of the initial object which you did use DontDestroyOnLoad as suggested by Bijan.Alox
Great, thanks :) I have a lot to learn on heritage! I did try (very hard) to dontDestroyOnLoad on the instansiated objects, but they would not hear of it. Even though they were made into GameObjects only one line above, they still said I cannot use "DontDestroyOnLoad" on Objects and that I could not explicitly or implecitly transform my "Object" to "GameObject" (even thought it was a GameObject to begin with).Allan Karseth

1 Answers

1
votes

In the initAcheivements function, either

testAch.transform.setParent(transform);

or

DontDestroyOnLoad(testAch);

Your problem is caused by the testAch either not being child of an object which wont be destroyed or the testAch not being an object itself which wont be destroyed.

In response to your comment, I quickly wrote this code and it didn't give me any issue, am I missing something possibly?

Vector3 loc = new Vector3(0f, 0f, 0f);
var testAch = Instantiate(myAchObject, loc, Quaternion.identity) as GameObject;
DontDestroyOnLoad(testAch);