Search Unity

[Unity 2D] How can I call a method on a clone of my current GameObject?

Discussion in 'Scripting' started by Warblingpants67, Apr 17, 2021.

  1. Warblingpants67

    Warblingpants67

    Joined:
    Jun 19, 2020
    Posts:
    17
    I'm trying to call a method on a clone of the GameObject the script is on. However, I always get a null Reference Exception. This is the line of code I'm trying to use to call the method:
    Code (CSharp):
    1. EnemysBattling.gameObject.transform.GetChild(1).gameObject.GetComponent<Enemy>().EnemyStartBattle();
    EnemysBattling is the parent GameObject of both the original and clone GameObjects, and Enemy is the script I'm trying to access. I'm not sure why this is happening, I get no errors in VSCode.
     
  2. If you can, store a reference to the other gameobject when you create the clone. That way you will always have a way to call on it.

    If you can't for some reason...

    If you guarantee that there aren't more than these two gameobjects under the parent you can do something like this:
    Code (CSharp):
    1. var index = transform.GetSiblingIndex() == 0 ? 1 : 0;
    2. var enemy = transform.parent.GetChild(index).GetComponent<Enemy>();
    3. enemy.EnemyStartBattle();
     
    Last edited by a moderator: Apr 17, 2021
  3. Warblingpants67

    Warblingpants67

    Joined:
    Jun 19, 2020
    Posts:
    17
    Ok, I just tried that now and I still got the same error. Maybe you aren't able to call a method on the clone from the original? Thanks for the help anyways!
     
  4. You're doing something wrong. I tested this, and it is working for me:
    screenshot1.png

    Child1 has 'Test.cs', Child 2 has 'Test2.cs' script on it.
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Test : MonoBehaviour
    4. {
    5.     void Update()
    6.     {
    7.         if (!Input.GetKeyUp(KeyCode.A)) return;
    8.         var index = transform.GetSiblingIndex() == 0 ? 1 : 0;
    9.         var enemy = transform.parent.GetChild(index).GetComponent<Test2>();
    10.         enemy.EnemyStartBattle();
    11.     }
    12. }
    13.  
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Test2 : MonoBehaviour
    4. {
    5.     public void EnemyStartBattle()
    6.     {
    7.         Debug.Log("Called");
    8.     }
    9. }
    10.  
    When I hit the 'A' key I get the log in the console:
    screenshot2.png

    ----
    How did you store the reference to the other game object exactly? That should work too.
     
    Last edited by a moderator: Apr 17, 2021
  5. Warblingpants67

    Warblingpants67

    Joined:
    Jun 19, 2020
    Posts:
    17
    It seems you may not fully understand what it is I'm trying to do. I have this gameObject that instantiates a clone of itself when a specific method is called. The problem I'm having is using the script on the original, to access the same script on the clone. Sorry if I wasn't totally clear about that in my original post ^^
     
  6. In this example you only have the Child1 in the editor and the Test component is attached to it.
    screenshot1.png screenshot2.png
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Test : MonoBehaviour
    4. {
    5.     // Start is called before the first frame update
    6.     void EnemyStartBattle()
    7.     {
    8.         Debug.Log("Called");
    9.     }
    10.  
    11.     void Update()
    12.     {
    13.         if (Input.GetKeyUp(KeyCode.A))
    14.         {
    15.             var index = transform.GetSiblingIndex() == 0 ? 1 : 0;
    16.             var enemy = transform.parent.GetChild(index).GetComponent<Test>();
    17.             enemy.EnemyStartBattle();
    18.         }
    19.  
    20.         if (Input.GetKeyUp(KeyCode.B))
    21.         {
    22.             Instantiate(this, transform.parent);
    23.             Debug.Log("Cloned.");
    24.         }
    25.     }
    26. }
    27.  
    The only thing to look out for is that you need to check that you execute the EnemyStartBattle only on the original game object, not on the clone one (in my example upon hitting A button, both game object executes it).


    If you do this, then you don't have to care about it:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Test : MonoBehaviour
    4. {
    5.     private Test clonedTest = null;
    6.  
    7.     // Start is called before the first frame update
    8.     void EnemyStartBattle()
    9.     {
    10.         Debug.Log("Called");
    11.     }
    12.  
    13.     void Update()
    14.     {
    15.         if (clonedTest != null && Input.GetKeyUp(KeyCode.A))
    16.         {
    17.             clonedTest.EnemyStartBattle();
    18.         }
    19.  
    20.         if (Input.GetKeyUp(KeyCode.B))
    21.         {
    22.             var go = Instantiate(this, transform.parent);
    23.             clonedTest = go.GetComponent<Test>();
    24.             Debug.Log("Cloned.");
    25.         }
    26.     }
    27. }
    28.  
    But be careful not to clone more than one, because the clone logic will run on every cloned object as well, so the number of clones will grow exponentially. Generally, it's more clean if you use two different game objects for the original and for the "enemy".
    You can also put the cloning logic on the parent instead of the Child1, so the cloning logic doesn't get cloned.
     
  7. Warblingpants67

    Warblingpants67

    Joined:
    Jun 19, 2020
    Posts:
    17
    Alright, thanks for the answer! I completely redid my code based on what you said here and now it works! Thank you so much :)
     
    Lurking-Ninja likes this.