I used a library to make this system, and everything works fine like taking damage, but I can’t change the fill amount of the healthbar. It’s under the enemy in the prefab, but I keep getting this error: Object reference not set to an instance of an object.
Here’s the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DC.HealthSystem;
public class ChaseAI : MonoBehaviour
{
public GameObject player;
public float speed;
private float distance;
// Update is called once per frame
public Health health;
public Image healthBar;
public GameObject fx;
void Start(){
player = GameObject.FindGameObjectWithTag("Player");
health = GetComponent<Health>();
healthBar = GetComponent<Image>();
}
void Update()
{
distance = Vector2.Distance(transform.position, player.transform.position);
Vector2 dir = player.transform.position - transform.position;
float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
transform.position = Vector2.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);
transform.rotation = Quaternion.Euler(Vector3.forward * angle);
}
public void OnDeath()
{
fx = GameObject.FindGameObjectWithTag("DeathFX");
Destroy(fx,.27f);
}
public void OnDamage()
{
healthBar.fillAmount -= (float)health.HealthValue/100;
}
}
No surprise actually … the above code has public fields and yet you are doing GetComponent()
This type of ambiguous design is just asking for future confusion.
You should pick one or the other, ideally public fields that you drag stuff into and then do not execute GetComponent() calls.
Here’s why:
Serialized / public fields in Unity are initialized as a cascade of possible values, each subsequent value (if present) overwriting the previous value:
what the class constructor makes (either default(T) or else field initializers, eg “what’s in your code”)
what may be saved with the prefab
what may be saved with the prefab override(s)/variant(s)
what may be saved in the scene and not applied to the prefab
what may be changed in the scene and not yet saved to disk
what may be changed in OnEnable(), Awake(), Start(), or even later
Make sure you only initialize things at ONE of the above levels, or if necessary, at levels that you specifically understand in your use case. Otherwise errors will seem very mysterious.
If you must initialize fields, then do so in the void Reset() method, which ONLY runs in the UnityEditor.
Here’s more nitty-gritty on serialization:
Field initializers versus using Reset() function and Unity serialization:
To avoid complexity in your prefabs / scenes, I recommend NEVER using the FormerlySerializedAsAttribute
Keep in mind that using GetComponent() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.
Don’t use all those Get/Find things unless you absolutely MUST use them. And when you do decide you’re ready to do it, here’s the bare minimum of stuff you absolutely MUST keep track of if you insist on using these crazy Ninja methods:
what you’re looking for:
→ one particular thing?
→ many things?
where it might be located (what GameObject?)
where the Get/Find command will look:
→ on one GameObject? Which one? Do you have a reference to it?
→ on every GameObject?
→ on a subset of GameObjects?
what criteria must be met for something to be found (enabled, named, etc.)
if your code expects one instance and later you have many (intentional or accidental), does it handle it?
If you are missing knowledge about even ONE of the things above, your call is likely to FAIL.
If you have issues, start debugging. We know the above methods will ALWAYS work so find out what you’re doing wrong before bothering to make a forum post.
This sort of coding is to be avoided at all costs unless you know exactly what you are doing.
Botched attempts at using Get- and Find- are responsible for more crashes than useful code, IMNSHO.
If you run into an issue with any of these calls, start with the documentation to understand why.
There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.
In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.
It is ALWAYS better to go The Unity Way™ and make dedicated public fields and drag in the references you want.