Search Unity

C# Reference to external GameObject null in Update()

Discussion in 'Scripting' started by ManuelHuber, Sep 9, 2017.

  1. ManuelHuber

    ManuelHuber

    Joined:
    Jul 3, 2017
    Posts:
    3
    Hi, I have a peculiar problem.
    My character game object has a AbilityHandler script. For abilities I create empty GameObjects, add the ability script and then save them as prefabs. Then I drag the ability prefab into the AbilityHandler of the character prefab.
    The AbilityHandler checks during update for hotkeys and calls the OnActivate method of the ability. If this returns false the ability isn't done yet (because it's waiting for a click). The OnActivate method also gets the reference to the character gameObject. But then in the update method of the Teleport script the reference to the character is suddenly null. But here's the strange thing: If the OnClick handler is called, the caster reference is no longer null. I added a Debug.Log to the Caster Property to see if it was being accessed, but it's only set once, during the OnActivation method.

    Why is the Caster Property null in the update method and then suddenly no longer null in the OnClick handler, if the reference hasn't been changed?!

    Code (CSharp):
    1. public class AbilityHandler : MonoBehaviour {
    2.     // I drag a list of prefabs containing the Ability Script into the field via inspector
    3.     public List<Ability> Abilities;
    4.    
    5.     public bool OnLeftClickUp(ClickLocation click) {
    6.         if (activeAbility == null || !activeAbility.OnLeftClickUp(click)) return false;
    7.         activeAbility = null;
    8.         return true;
    9.     }
    10.  
    11.     private void Update() {  
    12.         if (activeAbility != null) return;
    13.         Abilities.ForEach(ability => {
    14.             if (Input.GetKey(ability.Hotkey)) {
    15.                 activeAbility = ability;
    16.             }
    17.         });
    18.         // Here I give my teleport script a reference to the caster game object
    19.         if (activeAbility == null || !activeAbility.OnActivation(gameObject)) return;
    20.         activeAbility = null;
    21.     }
    22. }
    23.  
    24. public class Teleport : Ability {
    25.     public GameObject Caster {
    26.         get { return casterInternal; }
    27.         set {
    28.             // I'm logging access to the Caster property
    29.             Debug.Log("Setting: " + value);
    30.             casterInternal = value;
    31.         }
    32.     }
    33.     private GameObject casterInternal;
    34.  
    35.     public override bool OnActivation(GameObject cas) {
    36.         Debug.Log("OnActivation");
    37.         // We are setting the caster to a non-null value;
    38.         Caster = cas;
    39.         return false;
    40.     }
    41.  
    42.     public void Update() {
    43.         if (Caster == null) return;
    44.         Debug.Log("this statement will never be reached since the caster is null");
    45.     }
    46.  
    47.     public override bool OnLeftClickUp(ClickLocation click) {
    48.         if (Caster == null) return;
    49.         Debug.Log("On click the Caster is suddenly no longer null");
    50.         return true;
    51.     }
    52. }
    Here's the console output:

     
  2. ManuelHuber

    ManuelHuber

    Joined:
    Jul 3, 2017
    Posts:
    3
    Welp, like always I figured it out 5 minutes after asking for help (still would like confirmation though):
    The AbilityHandler was working directly with the Prefabs which is not what I wanted. Not 100% why it caused this exact behaviour though. The ability handler now actually Instantiates GameObjects for ability:

    Code (CSharp):
    1.     public class AbilityHandler : MonoBehaviour {
    2.         public List<GameObject> AbilityPrefabs;
    3.  
    4.         private readonly List<Ability> Abilities = new List<Ability>();
    5.        private void Awake() {
    6.             AbilityPrefabs.ForEach(o => Abilities.Add(Instantiate(o).GetComponent<Ability>()));
    7.         }
    8. }
    If there is a nicer way to handle this, let me know :)