Search Unity

Problem with Targetting script from BurgZergArcade Hack'N'Slash Tutorial

Discussion in 'Scripting' started by Latheeb, Oct 17, 2019.

  1. Latheeb

    Latheeb

    Joined:
    Jun 27, 2016
    Posts:
    21
    I'm trying to follow along with Peter Laliberte's Hack'N'Slash tutorial to help me learn the basics of Unity, but I've hit a problem I just can't figure out.

    I'm on part 52 of his video series:



    and I've only had minor issues until now.

    I have written a script called Targetting2 which is, for all intents and purposes, identical to script Peter writes in the above video. One difference is that, since FindChild is deprecated, I have used Find instead. I'm not sure if the lack of some other small change is causing my problem, or what.

    I have this script (Targetting2) added to a GameObject in my scene called __Game Master. His script called Mob I have named MobScript, which I attached to a prefab of a sphere, and added three of these spheres to the scene.

    My selectedTarget is changing as expected in the Inspector, but the name is not showing above my spheres and I am getting the following Error when I switch targets in Unity:

    NullReferenceException: Object reference not set to an instance of an object Targetting2.SelectTarget() (at Assets/Scripts/Targetting2.cs: 79)

    in reference to the line:

    name.GetComponent<TextMesh>().text = selectedTarget.GetComponent<MobScript>().Name;

    As I understand it, this means that it is not finding my script MobScript on the mob it is trying to target. Do I need to do something else to make up for not using FindChild?




    The relevant scripts:

    Targetting2:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class Targetting2 : MonoBehaviour
    5. {
    6.     public List<Transform> targets;
    7.     public Transform selectedTarget;
    8.     private Transform myTransform;
    9.     void Start()
    10.     {
    11.         targets = new List<Transform>();
    12.         AddAllEnemies();
    13.         selectedTarget = null;
    14.         myTransform = transform;
    15.     }
    16.     void Update()
    17.     {
    18.         if (Input.GetKeyDown(KeyCode.Tab))
    19.         {
    20.             TargetEnemy();
    21.         }
    22.     }
    23.     public void AddTarget(Transform enemy)
    24.     {
    25.         targets.Add(enemy);
    26.     }
    27.     public void AddAllEnemies()
    28.     {
    29.         GameObject[] go = GameObject.FindGameObjectsWithTag("Enemy");
    30.         foreach (GameObject enemy in go)
    31.             AddTarget(enemy.transform);
    32.     }
    33.     public void TargetEnemy()
    34.     {
    35.         if (selectedTarget == null)
    36.         {
    37.             SortTargetsByDistance();
    38.             selectedTarget = targets[0];
    39.         }
    40.         else
    41.         {
    42.             int index = targets.IndexOf(selectedTarget);
    43.             if (index < targets.Count - 1)
    44.             {
    45.                 index++;
    46.             }
    47.             else
    48.             {
    49.                 index = 0;
    50.             }
    51.             DeSelectTaraget();
    52.             selectedTarget = targets[index];
    53.         }
    54.         SelectTarget();
    55.     }
    56.     private void SortTargetsByDistance()
    57.     {
    58.         targets.Sort(delegate (Transform t1, Transform t2)
    59.         {
    60.             return (Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position)));
    61.         });
    62.     }
    63.     private void SelectTarget()
    64.     {
    65.         Transform name = selectedTarget.Find("Name");
    66.         if (name = null)
    67.         {
    68.             Debug.LogError("Could not find the name on " + selectedTarget.name);
    69.             return;
    70.         }
    71.         name.GetComponent<TextMesh>().text = selectedTarget.GetComponent<MobScript>().Name;
    72.         name.GetComponent<MeshRenderer>().enabled = true;
    73.     }
    74.     private void DeSelectTaraget()
    75.     {
    76.         selectedTarget.Find("Name").GetComponent<MeshRenderer>().enabled = false;
    77.         selectedTarget = null;
    78.     }
    79. }
    MobScript:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MobScript : BaseCharacter
    6. {
    7.     // Start is called before the first frame update
    8.     void Start()
    9.     {
    10.         GetPrimaryAttribute((int)AttributeName.Constitution).BaseValue = 100;
    11.         GetVital((int)VitalName.Health).Update();
    12.  
    13.         Name = "Slug Mob";
    14.     }
    15.  
    16.     // Update is called once per frame
    17.     void Update()
    18.     {
    19.         Messenger<int, int>.Broadcast("mob health update", 80, 100);
    20.     }
    21. }
    BaseCharacter:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;           // Adds to access enum class
    5.  
    6. public class BaseCharacter : MonoBehaviour
    7. {
    8.     private string _name;
    9.     private int _level;
    10.     private uint _freeExp;
    11.  
    12.     private Attribute[] _primaryAttribute;
    13.     private Vital[] _vital;
    14.     private Skill[] _skill;
    15.  
    16.     public void Awake()
    17.     {
    18.         _name = string.Empty;
    19.         _level = 0;
    20.         _freeExp = 0;
    21.  
    22.         _primaryAttribute = new Attribute[Enum.GetValues(typeof(AttributeName)).Length];
    23.         _vital = new Vital[Enum.GetValues(typeof(VitalName)).Length];
    24.         _skill = new Skill[Enum.GetValues(typeof(SkillName)).Length];
    25.  
    26.         SetupPrimaryAttributes();
    27.         SetupVitals();
    28.         SetupSkills();
    29.     }
    30. #region Getters and Setters
    31.     public string Name
    32.     {
    33.         get
    34.         {
    35.             return _name;
    36.         }
    37.         set
    38.         {
    39.             _name = value;
    40.         }
    41.     }
    42.     public int Level
    43.     {
    44.         get
    45.         {
    46.             return _level;
    47.         }
    48.         set
    49.         {
    50.             _level = value;
    51.         }
    52.     }
    53.     public uint FreeExp
    54.     {
    55.         get
    56.         {
    57.             return _freeExp;
    58.         }
    59.         set
    60.         {
    61.             _freeExp = value;
    62.         }
    63.     }
    64.     #endregion
    65.     public void AddExp(uint exp)
    66.     {
    67.         _freeExp += exp;
    68.         CalculateLevel();
    69.     }
    70.     public void CalculateLevel()        // Need to finish this
    71.     {
    72.  
    73.     }
    74.     private void SetupPrimaryAttributes()
    75.     {
    76.         for (int cnt = 0; cnt < _primaryAttribute.Length; cnt++)
    77.         {
    78.             _primaryAttribute[cnt] = new Attribute();
    79.             _primaryAttribute[cnt].Name = ((AttributeName)cnt).ToString();
    80.         }
    81.     }
    82.     private void SetupVitals()
    83.     {
    84.         for (int cnt = 0; cnt < _vital.Length; cnt++)
    85.         {
    86.             _vital[cnt] = new Vital();
    87.         }
    88.         SetupVitalModifiers();
    89.     }
    90.     private void SetupSkills()
    91.     {
    92.         for (int cnt = 0; cnt < _skill.Length; cnt++)
    93.         {
    94.             _skill[cnt] = new Skill();
    95.         }
    96.         SetupSkillModifiers();
    97.     }
    98.     public Attribute GetPrimaryAttribute(int index)
    99.     {
    100.         return _primaryAttribute[index];
    101.     }
    102.     public Vital GetVital(int index)
    103.     {
    104.         return _vital[index];
    105.     }
    106.     public Skill GetSkill(int index)
    107.     {
    108.         return _skill[index];
    109.     }
    110.     private void SetupVitalModifiers()
    111.     {
    112.         // health
    113.         GetVital((int)VitalName.Health).AddModifier(new ModifyingAttribute
    114.         { attribute = GetPrimaryAttribute((int)AttributeName.Constitution), ratio = 0.5f });
    115.         // energy
    116.         GetVital((int)VitalName.Energy).AddModifier(new ModifyingAttribute
    117.         { attribute = GetPrimaryAttribute((int)AttributeName.Constitution), ratio = 1f });
    118.         // mana
    119.         GetVital((int)VitalName.Mana).AddModifier(new ModifyingAttribute
    120.         { attribute = GetPrimaryAttribute((int)AttributeName.Willpower), ratio = 1f });
    121.     }
    122.     private void SetupSkillModifiers()
    123.     {
    124.         GetSkill((int)SkillName.Melee_Offense).AddModifier(new ModifyingAttribute
    125.         { attribute = GetPrimaryAttribute((int)AttributeName.Might), ratio = 0.33f });
    126.         GetSkill((int)SkillName.Melee_Offense).AddModifier(new ModifyingAttribute
    127.         { attribute = GetPrimaryAttribute((int)AttributeName.Nimbleness), ratio = 0.33f });
    128.         GetSkill((int)SkillName.Melee_Defense).AddModifier(new ModifyingAttribute
    129.         { attribute = GetPrimaryAttribute((int)AttributeName.Speed), ratio = 0.33f });
    130.         GetSkill((int)SkillName.Melee_Defense).AddModifier(new ModifyingAttribute
    131.         { attribute = GetPrimaryAttribute((int)AttributeName.Constitution), ratio = 0.33f });
    132.         GetSkill((int)SkillName.Ranged_Offense).AddModifier(new ModifyingAttribute
    133.         { attribute = GetPrimaryAttribute((int)AttributeName.Speed), ratio = 0.33f });
    134.         GetSkill((int)SkillName.Ranged_Offense).AddModifier(new ModifyingAttribute
    135.         { attribute = GetPrimaryAttribute((int)AttributeName.Concentration), ratio = 0.33f });
    136.         GetSkill((int)SkillName.Ranged_Defense).AddModifier(new ModifyingAttribute
    137.         { attribute = GetPrimaryAttribute((int)AttributeName.Speed), ratio = 0.33f });
    138.         GetSkill((int)SkillName.Ranged_Defense).AddModifier(new ModifyingAttribute
    139.         { attribute = GetPrimaryAttribute((int)AttributeName.Nimbleness), ratio = 0.33f });
    140.         GetSkill((int)SkillName.Magic_Offense).AddModifier(new ModifyingAttribute
    141.         { attribute = GetPrimaryAttribute((int)AttributeName.Willpower), ratio = 0.33f });
    142.         GetSkill((int)SkillName.Magic_Offense).AddModifier(new ModifyingAttribute
    143.         { attribute = GetPrimaryAttribute((int)AttributeName.Concentration), ratio = 0.33f });
    144.         GetSkill((int)SkillName.Magic_Defense).AddModifier(new ModifyingAttribute
    145.         { attribute = GetPrimaryAttribute((int)AttributeName.Willpower), ratio = 0.33f });
    146.         GetSkill((int)SkillName.Magic_Defense).AddModifier(new ModifyingAttribute
    147.         { attribute = GetPrimaryAttribute((int)AttributeName.Concentration), ratio = 0.33f });
    148.     }
    149.     public void StatUpdate()
    150.     {
    151.         for (int cnt = 0; cnt < _vital.Length; cnt++)
    152.             _vital[cnt].Update();
    153.         for (int cnt = 0; cnt < _skill.Length; cnt++)
    154.             _skill[cnt].Update();
    155.     }
    156. }
     
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    If the line
    Code (CSharp):
    1. name.GetComponent<TextMesh>().text = selectedTarget.GetComponent<MobScript>().Name;
    is throwing a NullreferenceException, then something on the right hand side of the assignment is null, such that you are accessing "null.something". Effectively this means that either selectedTarget is null, or it does not have a MobScript attached. To better debug this, i'd split this into multiple lines, which tells you exactly which of those is null.

    I highly doubt that the problem is caused by using "Find", since you dont use it to fill the target list if i didnt overlook it.
    That said, i would highly recomment you to not use "Find", "FindGameObjectWithTag" and any of those variantions at runtime. If you absolutely have to use it, then only do so once in Start() or Awake(), never in Update, as it is a very expensive operation which should never be necessary to use for anything other than prototyping in the first place.
     
  3. Latheeb

    Latheeb

    Joined:
    Jun 27, 2016
    Posts:
    21

    Thank you for the speedy response!

    Well, I can see the selectedTarget in the inspector and it indeed is switching between my three targets in that field, so I'm fairly certain that isn't null. The three spheres all have a MobScript on them, because the prefab they are made from has that script added to it. It may very well be some small typo I'm looking for, but I just can't seem to find it.

    As far as using Find. In this script, Find is used to find the MeshRenderer of the 3D Text Child on the sphere that displays the name of selectedTarget floating over it so that it can be enabled/disabled as targets switch.

    I have pressed ahead in the tutorial series hoping that maybe I had missed something (I had already watched the final part on making the targeting script, but I didn't see anything relevant) so I'll include the (mostly) final version of the script. Currently it correctly switches selectedTarget, but it does not display the health bar of the mob or the name of the mob.

    I still get exactly the same error (which is the primary error I'm trying to fix), as well as an additional error in line 90 of VitalsBar.cs:

    NullReferenceException: Object reference not set to an instance of an object Vitalsbar.ToggleDisplay (System.Boolean show) (at Assets/Scripts/HUD Scripts/VitalsBar.cs: 90)

    That line is:

    this.gameObject.GetComponent<Image>().enabled = show;

    which I added based on a youtube comment which suggested it worked in the current version of Unity, whereas the line used by Peter in the tutorial used deprecated code.

    I'm honestly fairly confused at this point. Fortunately I believe I can continue on with the tutorial series without fixing this problem (the targeting system should still work, I just can't see enemy healthbars currently) although I would very much like to figure out what is wrong.

    Otherwise I'll have to find some other system of health bar displays and hopefully cobble that in somehow.




    Updated Relevant Scripts (Just in case some change is significant although I think the problem areas have not been altered):

    Targetting2:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. public class Targetting2 : MonoBehaviour
    6. {
    7.     public List<Transform> targets;
    8.     public Transform selectedTarget;
    9.     private Transform myTransform;
    10.     void Start()
    11.     {
    12.         targets = new List<Transform>();
    13.         AddAllEnemies();
    14.         selectedTarget = null;
    15.         myTransform = transform;
    16.     }
    17.     void Update()
    18.     {
    19.         if (Input.GetKeyDown(KeyCode.Tab))
    20.         {
    21.             TargetEnemy();
    22.         }
    23.     }
    24.     public void AddTarget(Transform enemy)
    25.     {
    26.         targets.Add(enemy);
    27.     }
    28.     public void AddAllEnemies()
    29.     {
    30.         GameObject[] go = GameObject.FindGameObjectsWithTag("Enemy");
    31.         foreach (GameObject enemy in go)
    32.             AddTarget(enemy.transform);
    33.     }
    34.     public void TargetEnemy()
    35.     {
    36.         if (selectedTarget == null)
    37.         {
    38.             SortTargetsByDistance();
    39.             selectedTarget = targets[0];
    40.         }
    41.         else
    42.         {
    43.             int index = targets.IndexOf(selectedTarget);
    44.             if (index < targets.Count - 1)
    45.             {
    46.                 index++;
    47.             }
    48.             else
    49.             {
    50.                 index = 0;
    51.             }
    52.             DeSelectTaraget();
    53.             selectedTarget = targets[index];
    54.         }
    55.         SelectTarget();
    56.     }
    57.     private void SortTargetsByDistance()
    58.     {
    59.         targets.Sort(delegate (Transform t1, Transform t2)
    60.         {
    61.             return (Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position)));
    62.         });
    63.     }
    64.     private void SelectTarget()
    65.     {
    66.         Transform name = selectedTarget.Find("Name");
    67.         if (name = null)
    68.         {
    69.             Debug.LogError("Could not find the name on " + selectedTarget.name);
    70.             return;
    71.         }
    72.         name.GetComponent<TextMesh>().text = selectedTarget.GetComponent<MobScript>().Name;
    73.         name.GetComponent<MeshRenderer>().enabled = true;
    74.         selectedTarget.GetComponent<MobScript>().DisplayHealth();
    75.  
    76.         Messenger<bool>.Broadcast("show mob vital bars", true);
    77.     }
    78.     private void DeSelectTaraget()
    79.     {
    80.         selectedTarget.Find("Name").GetComponent<MeshRenderer>().enabled = false;
    81.         Messenger<bool>.Broadcast("show mob vital bars", false);
    82.         selectedTarget = null;
    83.     }
    84. }
    MobScript:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MobScript : BaseCharacter
    6. {
    7.     public int currentHealth;
    8.     public int maxHealth;
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.         GetPrimaryAttribute((int)AttributeName.Constitution).BaseValue = 100;
    13.         GetVital((int)VitalName.Health).Update();
    14.  
    15.         Name = "Slug Mob";
    16.     }
    17.  
    18.     // Update is called once per frame
    19.     void Update()
    20.     {
    21.     }
    22.     public void DisplayHealth()
    23.     {
    24.         Messenger<int, int>.Broadcast("mob health update", currentHealth, maxHealth);
    25.     }
    26. }
    VitalBar:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class VitalsBar : MonoBehaviour
    7. {
    8.     public bool _isPlayerHealthBar;                //This bool tells us if this is the player health bar or mob health bar
    9.     private int _maxBarLength;                      //How long the vital bar can be if the target is at 100% health
    10.     private int _currentBarLength;                  //This is how long the vital bar currently is
    11.     private RectTransform _display;
    12.     void Start()
    13.     {
    14.         _display = gameObject.GetComponent<RectTransform>();
    15. //        _isPlayerHealthBar = true;
    16.         _maxBarLength = (int)_display.rect.width;
    17.         OnEnable();
    18.     }
    19.     void Update()
    20.     {
    21.      
    22.     }
    23.     //This method is called when the GameObject is enabled
    24.     public void OnEnable()
    25.     {
    26.         if (_isPlayerHealthBar)
    27.         {
    28.             Messenger<int, int>.AddListener("player health update", OnChangeHealthBarSize);
    29.         }
    30.         else
    31.         {
    32.             ToggleDisplay(false);
    33.             Messenger<int, int>.AddListener("mob health update", OnChangeHealthBarSize);
    34.             Messenger<bool>.AddListener("show mob vital bars", ToggleDisplay);
    35.         }
    36.     }
    37.     //This method is called when the GameObject is enabled
    38.     public void OnDisable()
    39.     {
    40.         if (_isPlayerHealthBar)
    41.         {
    42.             Messenger<int, int>.RemoveListener("player health update", OnChangeHealthBarSize);
    43.         }
    44.         else
    45.         {
    46.             Messenger<int, int>.RemoveListener("mob health update", OnChangeHealthBarSize);
    47.             Messenger<bool>.RemoveListener("show mob vital bars", ToggleDisplay);
    48.         }
    49.     }
    50.     //This method will calculate the total size of the health bar in relation to the percentage of health the target
    51.     // has left
    52.     public void OnChangeHealthBarSize(int currentHealth, int maxHealth)
    53.     {
    54.         Debug.Log("We heard an event: Currenthealth = " + currentHealth + " Max Health = " + maxHealth);
    55.         _currentBarLength = (int)((currentHealth / (float)maxHealth) * _maxBarLength);            //Calculates the current bar length based on the characters health percentage
    56.         _display.sizeDelta = new Vector2(_currentBarLength, _display.rect.height);
    57.         _display.sizeDelta = CalculatePosition();
    58.     }
    59.  
    60.     //Setting the health bar to the player or mob
    61.     public void SetPlayerHealthBar(bool b)
    62.     {
    63.         _isPlayerHealthBar = b;
    64.     }
    65.     private Vector2 CalculatePosition()
    66.     {
    67.         float yPosition = _display.rect.height;
    68.  
    69.         if (!_isPlayerHealthBar)
    70.         {
    71.             float xPosition = (_maxBarLength - _currentBarLength) - ((_maxBarLength / 4) + 10);
    72.             return new Vector2(_currentBarLength, _display.rect.height);
    73.         }
    74.         if (_isPlayerHealthBar)
    75.         {
    76.             return new Vector2(_currentBarLength, _display.rect.height);
    77.         }
    78.         else return new Vector2(0, 0);
    79.     }
    80.     private void ToggleDisplay(bool show)
    81.     {
    82.         this.gameObject.GetComponent<Image>().enabled = show;
    83.     }
    84. }
    BaseCharacter:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;           // Adds to access enum class
    5.  
    6. public class BaseCharacter : MonoBehaviour
    7. {
    8.     private string _name;
    9.     private int _level;
    10.     private uint _freeExp;
    11.  
    12.     private Attribute[] _primaryAttribute;
    13.     private Vital[] _vital;
    14.     private Skill[] _skill;
    15.  
    16.     public void Awake()
    17.     {
    18.         _name = string.Empty;
    19.         _level = 0;
    20.         _freeExp = 0;
    21.  
    22.         _primaryAttribute = new Attribute[Enum.GetValues(typeof(AttributeName)).Length];
    23.         _vital = new Vital[Enum.GetValues(typeof(VitalName)).Length];
    24.         _skill = new Skill[Enum.GetValues(typeof(SkillName)).Length];
    25.  
    26.         SetupPrimaryAttributes();
    27.         SetupVitals();
    28.         SetupSkills();
    29.     }
    30. #region Getters and Setters
    31.     public string Name
    32.     {
    33.         get
    34.         {
    35.             return _name;
    36.         }
    37.         set
    38.         {
    39.             _name = value;
    40.         }
    41.     }
    42.     public int Level
    43.     {
    44.         get
    45.         {
    46.             return _level;
    47.         }
    48.         set
    49.         {
    50.             _level = value;
    51.         }
    52.     }
    53.     public uint FreeExp
    54.     {
    55.         get
    56.         {
    57.             return _freeExp;
    58.         }
    59.         set
    60.         {
    61.             _freeExp = value;
    62.         }
    63.     }
    64.     #endregion
    65.     public void AddExp(uint exp)
    66.     {
    67.         _freeExp += exp;
    68.         CalculateLevel();
    69.     }
    70.     public void CalculateLevel()        // Need to finish this
    71.     {
    72.  
    73.     }
    74.     private void SetupPrimaryAttributes()
    75.     {
    76.         for (int cnt = 0; cnt < _primaryAttribute.Length; cnt++)
    77.         {
    78.             _primaryAttribute[cnt] = new Attribute();
    79.             _primaryAttribute[cnt].Name = ((AttributeName)cnt).ToString();
    80.         }
    81.     }
    82.     private void SetupVitals()
    83.     {
    84.         for (int cnt = 0; cnt < _vital.Length; cnt++)
    85.         {
    86.             _vital[cnt] = new Vital();
    87.         }
    88.         SetupVitalModifiers();
    89.     }
    90.     private void SetupSkills()
    91.     {
    92.         for (int cnt = 0; cnt < _skill.Length; cnt++)
    93.         {
    94.             _skill[cnt] = new Skill();
    95.         }
    96.         SetupSkillModifiers();
    97.     }
    98.     public Attribute GetPrimaryAttribute(int index)
    99.     {
    100.         return _primaryAttribute[index];
    101.     }
    102.     public Vital GetVital(int index)
    103.     {
    104.         return _vital[index];
    105.     }
    106.     public Skill GetSkill(int index)
    107.     {
    108.         return _skill[index];
    109.     }
    110.     private void SetupVitalModifiers()
    111.     {
    112.         // health
    113.         GetVital((int)VitalName.Health).AddModifier(new ModifyingAttribute
    114.         { attribute = GetPrimaryAttribute((int)AttributeName.Constitution), ratio = 0.5f });
    115.         // energy
    116.         GetVital((int)VitalName.Energy).AddModifier(new ModifyingAttribute
    117.         { attribute = GetPrimaryAttribute((int)AttributeName.Constitution), ratio = 1f });
    118.         // mana
    119.         GetVital((int)VitalName.Mana).AddModifier(new ModifyingAttribute
    120.         { attribute = GetPrimaryAttribute((int)AttributeName.Willpower), ratio = 1f });
    121.     }
    122.     private void SetupSkillModifiers()
    123.     {
    124.         GetSkill((int)SkillName.Melee_Offense).AddModifier(new ModifyingAttribute
    125.         { attribute = GetPrimaryAttribute((int)AttributeName.Might), ratio = 0.33f });
    126.         GetSkill((int)SkillName.Melee_Offense).AddModifier(new ModifyingAttribute
    127.         { attribute = GetPrimaryAttribute((int)AttributeName.Nimbleness), ratio = 0.33f });
    128.         GetSkill((int)SkillName.Melee_Defense).AddModifier(new ModifyingAttribute
    129.         { attribute = GetPrimaryAttribute((int)AttributeName.Speed), ratio = 0.33f });
    130.         GetSkill((int)SkillName.Melee_Defense).AddModifier(new ModifyingAttribute
    131.         { attribute = GetPrimaryAttribute((int)AttributeName.Constitution), ratio = 0.33f });
    132.         GetSkill((int)SkillName.Ranged_Offense).AddModifier(new ModifyingAttribute
    133.         { attribute = GetPrimaryAttribute((int)AttributeName.Speed), ratio = 0.33f });
    134.         GetSkill((int)SkillName.Ranged_Offense).AddModifier(new ModifyingAttribute
    135.         { attribute = GetPrimaryAttribute((int)AttributeName.Concentration), ratio = 0.33f });
    136.         GetSkill((int)SkillName.Ranged_Defense).AddModifier(new ModifyingAttribute
    137.         { attribute = GetPrimaryAttribute((int)AttributeName.Speed), ratio = 0.33f });
    138.         GetSkill((int)SkillName.Ranged_Defense).AddModifier(new ModifyingAttribute
    139.         { attribute = GetPrimaryAttribute((int)AttributeName.Nimbleness), ratio = 0.33f });
    140.         GetSkill((int)SkillName.Magic_Offense).AddModifier(new ModifyingAttribute
    141.         { attribute = GetPrimaryAttribute((int)AttributeName.Willpower), ratio = 0.33f });
    142.         GetSkill((int)SkillName.Magic_Offense).AddModifier(new ModifyingAttribute
    143.         { attribute = GetPrimaryAttribute((int)AttributeName.Concentration), ratio = 0.33f });
    144.         GetSkill((int)SkillName.Magic_Defense).AddModifier(new ModifyingAttribute
    145.         { attribute = GetPrimaryAttribute((int)AttributeName.Willpower), ratio = 0.33f });
    146.         GetSkill((int)SkillName.Magic_Defense).AddModifier(new ModifyingAttribute
    147.         { attribute = GetPrimaryAttribute((int)AttributeName.Concentration), ratio = 0.33f });
    148.     }
    149.     public void StatUpdate()
    150.     {
    151.         for (int cnt = 0; cnt < _vital.Length; cnt++)
    152.             _vital[cnt].Update();
    153.         for (int cnt = 0; cnt < _skill.Length; cnt++)
    154.             _skill[cnt].Update();
    155.     }
    156. }



    Edit:

    Also, upon further testing I've noticed that if I enable the Mesh Renderer on the 3D Text for the name it will disappear if I deselect the mob, but it will not rename them as it should (They have the standard "Hello World" as names instead of being renamed to "Slug Mob") and the renderer is not enabled when they are selected. At least part of it is working, just not the important part.

    Still no luck on the HP Bar, though.
     
    Last edited: Oct 17, 2019
  4. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    Please do as i suggested and use Debug.Log to easily find what's null in the lines in question, by splitting them into multiple lines. For example i assume that there is no Image Component on whatever is calling the corresponding line. To find this out, you can split it up into multiple lines and check for null as such:
    Code (CSharp):
    1. var component = this.gameObject.GetComponent<Image>();
    2.  
    3. if(component == null){
    4.     Debug.Log("We are missing an Image Component but try to access one of its fields");
    5. }
    6.  
    7. component.enabled = show;
    Now you would be able to see in the console if the object that is trying to access the image component, does not have an image component. Do something similar for your other error location and find what's actually null that way. You are probably just doing something you are not aware of, like having the script on two objects, one of which does not have the component you are trying to access, or something along those lines.

    Hope this helps :)
     
  5. Latheeb

    Latheeb

    Joined:
    Jun 27, 2016
    Posts:
    21

    I really appreciate the input and I'm sorry to have not responded sooner, but I've had other things going on and hadn't made it back around to trying to fix this particular problem until a little while ago.

    I modified SelectedTarget to be:

    Code (CSharp):
    1. private void SelectTarget()
    2.     {
    3.         Transform name = selectedTarget.Find("Name");
    4.         if (name = null)
    5.         {
    6.             Debug.LogError("Could not find the name on " + selectedTarget.name);
    7.             return;
    8.         }
    9.         var nameText = name.GetComponent<TextMesh>().text;
    10.         if(nameText == null)
    11.         {
    12.             Debug.Log("Trying to get the Text Mesh but it doesn't exist");
    13.         }
    14.         else if (nameText != null)
    15.         {
    16.             Debug.Log(nameText);
    17.         }
    18.         nameText = selectedTarget.GetComponent<MobScript>().Name;
    19.         name.GetComponent<MeshRenderer>().enabled = true;
    20.         selectedTarget.GetComponent<MobScript>().DisplayHealth();
    21.         Messenger<bool>.Broadcast("show mob vital bars", true);
    22.     }
    I'm getting the null reference error on the line:

    var _name = name.GetComponent<TextMesh>().text;

    I guess this means that it can't find the Text Mesh associated with the "Name" child on my mob? Oddly, I'm not getting any Debug.Log messages from this script at all. I'm still very confused as to why it's disabling the Mesh Renderer when I deselect my target, yet not enabling it when the target is selected, even though the code should be functionally identical.
     
  6. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    Yes, that means you do not have a TextMesh component on the gameobject the "name" transform belongs to.

    As for why your script does not throw an exception, that's actually rather simple. At line 9 you are getting the component, and then accessing its text field in the same line. So you are basically calling null.text, which throws the NullReferenceException and stops the program. Thus the line afterwards, which would print the Debug.Log(), never gets called. So instead you should have one test for getting the component and checking if it's null, and one for the text afterwards.

    Also, just to be clear, you only want this for debugging purposes. So after we are done, you can remove these code lines. As such, it's probably easier (or rather faster) to just write something like this:
    Code (CSharp):
    1. Debug.Log("Component is null: " + (component == null));
    Instead of the if-statement. Both works, but i find this more clean and fast for debugging purposes. Technically you could always use the actual debugger to debug code without Debug.Log(), but for quick checks i like to use it.
     
  7. Latheeb

    Latheeb

    Joined:
    Jun 27, 2016
    Posts:
    21
    I'm a little confused by what you mean by setting up onetest for getting the component and another for checking if it's null. I tried:

    Code (CSharp):
    1. private void SelectTarget()
    2.     {
    3.         Transform name = selectedTarget.Find("Name");
    4.         if (name = null)
    5.         {
    6.             Debug.LogError("Could not find the name on " + selectedTarget.name);
    7.             return;
    8.         }
    9.         var _name = name.GetComponent<TextMesh>();
    10.         if(_name == null)
    11.         {
    12.             Debug.Log("Trying to get the Text Mesh but it doesn't exist");
    13.         }
    14.         else if (_name != null)
    15.         {
    16.             Debug.Log(_name);
    17.         }
    18.         var nameText = name.GetComponent<TextMesh>().text;
    19.  
    20.         nameText = selectedTarget.GetComponent<MobScript>().Name;
    21.         name.GetComponent<MeshRenderer>().enabled = true;
    22.         selectedTarget.GetComponent<MobScript>().DisplayHealth();
    23.  
    24.         Messenger<bool>.Broadcast("show mob vital bars", true);
    25.     }
    But I seem to be misunderstanding what you're saying.

    As to the main problem I'm confused as to why the Text Mesh component would return null as "Name" has a Text Mesh. I'm instantiating a mob prefab that has a child "Name" when the scene is loaded and that child has a Text Mesh. Could the fact that this mob is instantiated using a script when the scene is loaded be causing a problem?
     
  8. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    What i meant was that it's easier to write it like this, and also to do it step-by-step:
    Code (CSharp):
    1. Debug.Log(name.gameObject.name + " was found as child.");
    2. var component = name.GetComponent<TextMesh>();
    3. Debug.Log("Component was found: " + !(component == null));
    4. var name = component.text;
    5. Debug.Log("The text found was: " + name);
    6. // and so on.
    7. // that way you directly see in the console each step and thus where it's going wrong
    8. // and it's a bit cleaner and faster than having null check if-statements between each line
    Sorry if i confused you somehow.

    Instantiating things through script should not cause problems. You are trying to find a child called "Name", then find its TextMesh component, then access that components' text field. Somewhere in this chain, things should be different from what you expect. For example, maybe selectTarget.Find("Name") may not actually find the correct child (or a child at all), possibly due to misspelling or other human errors (like checking the wrong object for its child). That's one possible explanation for why the child seemingly does not have a TextMesh component but you think it should.

    Edit: I just noticed that you wrote name = null, instead of name == null in your first check. So basically.. you are not checking for null, but assigning null, which also explains why GetComponent throws a NullReferenceException. At that point, name is always null. Removing your first "check" may fix your problem.
     
  9. Latheeb

    Latheeb

    Joined:
    Jun 27, 2016
    Posts:
    21

    Thank you for being so patient with me. I must really seem dense by now. I'm honestly completely unsure of what was causing the problem originally (or if I put that original name = null line in early on and that was causing it from the start) but everything is working as I would expect, now.

    Also I really appreciate your tips regarding ways to write cleaner or more efficient code you've given each time you've given an explanation. You've not only helped me fix the problem I was having but also hopefully to write better code in the future.
     
  10. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    Dont feel bad or dense. These things happen. After all, i only did notice it after what? The like 10th post? And it was there from the beginning. That's just something i dont look at since i assume it's done right. Probably the same for you, as you did it right the following times, but typos do happen, so no need to feel bad about it. Just glad we figured it out! :)

    Wish you a great day and good luck with the rest of your project!