Returns NaN when referencing function from another script

So I’m a beginner to unity. My first game i’m making is a top-down shooter game. The enemy chases the player and shoots bullets at him. I have a HealthSystem script that manages all the damages and heals and in it, I have a function called Damage(). Inside my projectile script, I reference the Damage() function in my projectile script. The problem is, when I try to Debug.Log my health, it returns NaN. The function works fine in my Game Handler script though. The GameHandeler and HealthSystem script are both on an empty gameobject and the projectile script is on a bullet prefab.


Ill include my GameHandler, HealthSystem, and Projectile Scripts.

Projectile

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour {

    public float speed;

    private Transform player;
    private Vector2 target;

    public HealthSystem healthSystem;
 

    public void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player").transform;

        target = new Vector2(player.position.x, player.position.y);

        healthSystem = GameObject.Find("GameHandler").GetComponent<HealthSystem>();

    }

    public void Update()
    {
        transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);

            if (transform.position.x == target.x && transform.position.y == target.y)
            {
                DestroyProjectile();
            }
    }

    public void OnTriggerEnter2D(Collider2D other)
    {
            if (other.CompareTag("Player"))
            {
                DestroyProjectile();
                healthSystem.Damage(10);
                Debug.Log("Health: " + healthSystem.GetHealthPercent());
            }
    }
    
     public void DestroyProjectile()
     {
            Destroy(gameObject);
     }
}

Additional Question: I have to create reference to the script to use healthSystem.Damage(), but in the GameHandeler, I don’t have to. Is it because they are on the same object?


GameHandeler

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameHandeler : MonoBehaviour {

    public Transform pfHealthBar;
    private Transform player;

    public void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player").transform;
        HealthSystem healthSystem = new HealthSystem(100);

        Transform healthBarTransform = Instantiate(pfHealthBar, new Vector3(0, 1), Quaternion.identity);
        HealthBar healthBar = healthBarTransform.GetComponent<HealthBar>();
        healthBarTransform.transform.parent = player;
        healthBar.Setup(healthSystem);


        Debug.Log("Health: " + healthSystem.GetHealthPercent());
        healthSystem.Damage(10);
        Debug.Log("Health: " + healthSystem.GetHealthPercent());
        healthSystem.Heal(10);
        Debug.Log("Health: " + healthSystem.GetHealthPercent());

    }

}

###HealthSystem

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class HealthSystem : MonoBehaviour
{

    public event EventHandler OnHealthChanged;
    private int health;
    private int healthMax;

    public HealthSystem(int healthMax)
    {
        this.healthMax = healthMax;
        health = healthMax;
    }

    public int GetHealth()
    {
        return health;
    }

    public float GetHealthPercent()
    {
        return (float)health / healthMax;
    }

    public void Damage(int damageAmount)
    {
        health -= damageAmount;
        if (health < 0) health = 0;
        if (OnHealthChanged != null) OnHealthChanged(this, EventArgs.Empty);
    }

    public void Heal(int healAmount)
    {
        health += healAmount;
        if (health > healthMax) health = healthMax;
        if (OnHealthChanged != null) OnHealthChanged(this, EventArgs.Empty);
    }


}

I got the Projectile script from a

Hi,

Appearently, your healhtMax is not set, which is why on GetHealthPercentage() your current health gets divided by 0 => NaN.

I think this is caused by two different health systems that you create. I cant say for sure, but I assume you already assigned a HealthSystem component to your GameHandler object in the editor, right? So, on starting the game, your GameHandler.Start() function creates a new HealthSystem with HealthSystem healthSystem = new HealthSystem(100);.

The problem now is that you look for the HealthSystem component in your Projectile on Start(). I again assume projectiles are created at runtime, so Projectile.Start() will be called later than GameHandler.Start(). Now, as you assigned a HealthSystem and created a new HealthSystem with your function call, the projectile only assigns the first one. Which has an unset MaxHealth, as only your second HealthSystem was initialized properly.

Takeaway: Don’t create something deriving from MonoBehaviour with a “new XYZ()” call. If you are using VisualStudio, it should flag this.
If you did not assign a HealthSystem in the Editor, so you dont create two, this is probably still the cause.

You should be using

HealthSystem hs = AddComponent<HealthSystem>();
hs.SetMaxHP(100);

instead (or add the component via the editor)