Unable to swap GameObjects properly (and possible Unity 5 bug)

Hello all!

I’m having a lot of headache figuring out this one…
So, I’m build a JRPG battle style, and this has an option to swap characters in battle with characters in reserve during it. The code is basically this:

IEnumerator RetreatAction () {

        GameObject ReserveChar;
        ReserveChar = CharactersInParty[5];
        CharactersInParty[5] = characters[1].gameObject;
        CharactersInParty[1] = ReserveChar;
        yield return new WaitForSeconds(0.2f);
        Destroy(characters[1].gameObject);
        characters[1] = ((GameObject)Instantiate(ReserveChar, new Vector2(characters[1].transform.position.x, characters[1].transform.position.y), Quaternion.identity)).GetComponent<CharacterStats>();               
    }

What’s happening above is basically swapping spots. CharactersInParty is a list of GameObjects Prefabs representing the total of characters that can be used, and “characters” are the 4 characters currently instantiated in battle (as CharacterStats class, not GameObjects). So I need to swap places in CharactersInParty, and I also need to instantiate a new GameObject (with CharacterStats component) in the replaced “characters”.

Code is working fine, but when Destroy triggers, it’s not only destroying characters[1], it’s also destroys CharactersInParty[5], and I can’t figure out why! CharactersInParty is not touched anywhere else in the code.

Above you can see the bug I mentioned, element 5 should be updated to null on Inspector as soon as Destroy triggers, but it does only if I click it (took me an hour to notice it…). In Debug.Log I’m able to see it as null correctly.

If someone could please shed some light on this, I would appreciate it.

Thank you in advance :slight_smile:

You set characers[1] to ReserveChar (which is CharactersInParty[5]), then destroy it (which would make it null) and then Instantiate using ReserveChar which is now null.

I’m Destroying characters[1] AFTER I set up it in CharactersInParty[5], so it wasn’t null at the point of setup.

If I perform the same debug right after the code above, there’s nothing null, everything is setup perfectly. By the end of the frame, when Destroy actually occours, then CharactersInParty[5] becomes null.

Why is Destroy targeting CharactersInParty[5] AND characters[1]?

You set CharactersInParty[5] to characters[1] and then destroy characters[1]. GameObjects are reference types so setting it to some index in an array doesn’t copy it or anything.

If you do this then you should get True in your console

Debug.Log(CharactersInParty[5] == characters[1].gameObject);

I think you are confused about reference types and value types.
GameObject is a class and classes are reference type. That means when you assign one into a variable there is no “point of setup” and there is no second object created. The only thing that is done is to copy the reference of a single object.

IEnumerator RetreatAction () {
        GameObject ReserveChar;
        ReserveChar = CharactersInParty[5];

GameObject is a reference type. That means CharactersInParty[5] is not actually a GameObject, it is a memory address which “points” to the GameObject. When you assign it to ReserveChar, the GameObject is not duplicated, instead the memory address is copied such that both variables now refer to the same object.

Let’s remove some of the code so it’s clear what is happening:

CharactersInParty[5] = characters[1].gameObject;
// ...
Destroy(characters[1].gameObject);
// ...

Since both variables refer to the same object, it should be clear that CharactersInParty[5] is going to get destroyed.

1 Like

@Eisen , that makes sense, I imaged it could be something like this.

But then, how can I destroy the GameObject on the scene without also destroying it’s reference?

I suppose I could assign the Prefab to CharactersInParty (instead of the Instatiated GameObject), but I’m not a big fan of pulling Prefabs directly from code unless absolutely necessary.

I think you’ve got your object lists mixed up. I can’t be certain from just this snippit but I’m guessing CharactersInParty is supposed to be a list of templates which you copy into the battle. In that case, your mistake is on line 5.

IEnumerator RetreatAction () {

        GameObject ReserveChar;
        ReserveChar = CharactersInParty[5];
        CharactersInParty[5] = characters[1].gameObject;
        CharactersInParty[1] = ReserveChar;
        yield return new WaitForSeconds(0.2f);
        Destroy(characters[1].gameObject);
        characters[1] = ((GameObject)Instantiate(ReserveChar, new Vector2(characters[1].transform.position.x, characters[1].transform.position.y), Quaternion.identity)).GetComponent<CharacterStats>();           
    }

You are overwriting the template item with the character in the battle. I think line 5 should be:

CharactersInParty[5] = CharactersInParty[1];

That said, I find it pretty strange that you need to swap the order of your characters at all…

You’re absolutely right! I should have thinked about that :slight_smile:

Thank you sir, appreciate it, everything works now :slight_smile: