Health Bars of Enemies are linked together

So I’m working on an RPG and right now I have combat down and I have enemies spawning from a spawner that I placed in the scene and that spawner has an array of the enemies it is going to spawn, and when the player get close enough to the spawner it spawns some enemies. Each of these enemies has a health bar over them that I created with a canvas and made it a child of the enemy (the enemies are all prefabs with the same scripts attached to them). The health bar sliders also have a script attached to them for displaying the health bar as it goes down when taking damage, but for some reason when the player deals damage, the health bars don’t go down EXCEPT for one of the enemy prefabs, which if that one takes damage the rest of the enemy health bars go down. They don’t die when the “original” one does as they’re healths are separate from the original but the slider itself doesn’t change on the rest.

Can anyone help me figure out why this is happening (if this makes sense)

Enemy Health Script (on Enemy)

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

public class EnemyHealth : MonoBehaviour
{
    public Slider enemySlider3D;
    Stats stats;

    // Start is called before the first frame update
    void Start()
    {
        stats = GameObject.FindGameObjectWithTag("Enemy").GetComponent<Stats>();
        enemySlider3D = GetComponent<Slider>();

        enemySlider3D.maxValue = stats.maxHealth;
        stats.health = stats.maxHealth;
    }

    // Update is called once per frame
    void Update()
    {
        enemySlider3D.value = stats.health;
    }
}

Combat Script (on Player)

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

public class Combat : MonoBehaviour
{
    public enum PlayerType { Melee, Ranged }
    public PlayerType playerType;
    public float attackRange;
    public float rotateSpeedForAttack;
    private Movement moveScript;
    public bool basicAtkIdle = false;
    public bool isHeroAlive;
    public bool performMeleeAttack = true;
    Animator anim;
    Stats stats;
    public GameObject enemy;
    float rotateVelocity;
   

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();
        moveScript = GetComponent<Movement>();
        stats = GetComponent<Stats>();
    }

    // Update is called once per frame
    void Update()
    {
        if(enemy != null)
        {
            if(Vector3.Distance(gameObject.transform.position, enemy.transform.position) > attackRange)
            {
                transform.Translate(new Vector3(0, 0, moveScript.verticalInput) * moveScript.moveSpeed * Time.deltaTime);
                anim.SetFloat("Speed", moveScript.verticalInput);

                Quaternion rotationToLookAt = Quaternion.LookRotation(enemy.transform.position - transform.position);
                float rotationY = Mathf.SmoothDampAngle(transform.eulerAngles.y,
                    rotationToLookAt.eulerAngles.y,
                    ref rotateVelocity,
                    rotateSpeedForAttack * (Time.deltaTime * 5));

                transform.eulerAngles = (new Vector3(0, rotationY, 0));
            }

            else
            {
                if(playerType == PlayerType.Melee)
                {
                    if (performMeleeAttack)
                    {
                        StartCoroutine(MeleeAttackInterval());
                    }
                }
            }
        }
    }

    IEnumerator MeleeAttackInterval()
    {
        performMeleeAttack = false;
        anim.SetBool("Attack", true);

        yield return new WaitForSeconds(stats.atkTime / ((100 + stats.atkTime) * 0.01f));

        if(enemy == null)
        {
            anim.SetBool("Attack", false);
            performMeleeAttack = true;
        }
    }

    public void MeleeAttack()
    {
        if(enemy != null)
        {
            if(enemy.GetComponent<Targetable>().minion == Targetable.EnemyType.Minion)
            {
                enemy.GetComponent<Stats>().health -= stats.atkDmg;
            }
        }

        performMeleeAttack = true;
    }
}

Enemy Spawner Script (on Capsule Game Object)

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

public class EnemySpawner : MonoBehaviour
{
    Vector3 spawnPos;
    public GameObject[] enemySpawn;
    public Transform player;
    public float range;
    int count;
    int[] angles = { 15, 120, 150};
 
    // Start is called before the first frame update
    void Start()
    {
        count = enemySpawn.Length;
    }

    // Update is called once per frame
    void Update()
    {
        if(Vector3.Distance(transform.position, player.position) < range)
        {
            for(int i = 0; i < enemySpawn.Length; i++)
            {
                if(count != 0)
                {
                    Spawn(angles[i], enemySpawn[0]);
                    count--;
                }
            }
        }
    }

    void Spawn(int angle, GameObject spawnNum)
    {
        Vector3 direction = Quaternion.Euler(0, angle, 0) * Vector3.right;
        spawnPos = transform.position + direction * 2;
        Instantiate(spawnNum, spawnPos, Quaternion.identity);
    }
}

Stats Script (on both enemy and player)

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

public class Stats : MonoBehaviour
{
    public int lvl;
    public float health;
    public float maxHealth;
    public int mana;
    public int atkDmg;
    public int magDef;
    public int physDef;
    public float atkSpeed;
    public float atkTime;

    Combat combatScript;

    // Start is called before the first frame update
    void Start()
    {
        combatScript = GameObject.FindGameObjectWithTag("Player").GetComponent<Combat>();
    }

    // Update is called once per frame
    void Update()
    {
        if(health <= 0)
        {
            Destroy(this.gameObject);
            combatScript.enemy = null;
            combatScript.performMeleeAttack = false;
        }
    }
}
        stats = GameObject.FindGameObjectWithTag("Enemy").GetComponent<Stats>();

Which enemy do you think this is going to find? If the EnemyHealth script is attached to the enemy, then why are you going to the effort of finding a enemy with the enemy tag?

FindGameObjectWithTag will find a single gameobject with that tag. If you have multiple objects with that tag, and you need a specific one of the gameobjects, then you need a different way of finding that specific gameobject.

Since your EnemyHealth is attached to your Enemy, you should just be able to replace the line above with

stats = gameObject.GetComponent<Stats>();

Which will try to get the Stats component from the Enemy that that script is attached to (instead of an arbitrary enemy.

1 Like