Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question Enemy is losing 2 health instead of 1

Discussion in 'Scripting' started by NatiSFG, Mar 21, 2023.

  1. NatiSFG

    NatiSFG

    Joined:
    Jul 21, 2017
    Posts:
    24
    I am trying to componentize all of my scripts and I would like the enemy to lose 1 health (enemy max health is 3) every time the player collides with the enemy. Right now the enemy is losing 2 health instead of 1. This is my hierarchy for the enemy:



    There is Health and Take Damage On Collision scripts under the Enemy gameObject and a Health Bar script under the Health Bar gameObject.


    Enemy gameObject


    Health Bar gameObject

    Perhaps there's code running one in two separate places? I know OnCollisionEnter2D runs every frame but that's why I created a damageInterval. Here are my scripts:

    Code (CSharp):
    1. public class Health : MonoBehaviour {
    2.  
    3.     public int maxHealth;
    4.     public int currentHealth;
    5.  
    6.     void Start() {
    7.         currentHealth = maxHealth;
    8.     }
    9. }

    Code (CSharp):
    1. public class HealthBar : MonoBehaviour {
    2.  
    3.     [SerializeField] private GameObject character;
    4.     public Slider slider;
    5.     public Gradient gradient;
    6.     public Image fill;
    7.  
    8.     private void Start() {
    9.         Health health = character.GetComponent<Health>();
    10.         HealthBar healthBar = gameObject.GetComponent<HealthBar>();
    11.         healthBar.SetMaxHealth(health.maxHealth);
    12.     }
    13.  
    14.     public void SetMaxHealth(int health) {
    15.         slider.maxValue = health;
    16.         slider.value = health;
    17.  
    18.         /*on the gradient that has (left to right) red, yellow and green fixed portions,
    19.         all the way to the left 0f (red), and all the way to the right 1f (green)
    20.         we assign the entire fill of the HealthBar to this color
    21.         */
    22.         fill.color = gradient.Evaluate(1f);
    23.     }
    24.  
    25.     public void SetHealth(int health) {
    26.         slider.value = health;
    27.  
    28.         /*we assign the entire fill of the HealthBar to the normalized value (0 to 1) so
    29.         //the 0 to 10 points of health syncs with 0 to 1 on the gradient. this determines
    30.         what color the fill will be depending on how much health is left
    31.         */
    32.         fill.color = gradient.Evaluate(slider.normalizedValue);
    33.     }
    34. }

    Code (CSharp):
    1. public class TakeDamage : MonoBehaviour {
    2.  
    3.     private float damageInterval = 2f;
    4.     private float currentDamageInterval;
    5.  
    6.     private void Update() {
    7.         if(currentDamageInterval >= 0)
    8.             currentDamageInterval -= Time.deltaTime;
    9.     }
    10.  
    11.     public bool CanTakeDamage() {
    12.         return (currentDamageInterval < 0);
    13.     }
    14.  
    15.     public void EnemyTakeDamage(int damageAmount) {
    16.         Health health = gameObject.GetComponent<Health>();
    17.  
    18.         if(gameObject.CompareTag("Hazard") && CanTakeDamage()) {
    19.             health.currentHealth -= damageAmount;
    20.             currentDamageInterval = damageInterval;
    21.             if (health.currentHealth <= 0)
    22.                 Destroy(gameObject);
    23.         }
    24.     }
    25. }

    Code (CSharp):
    1. public class TakeDamageOnCollision : MonoBehaviour {
    2.  
    3.     [SerializeField] private int damageAmount;
    4.     [SerializeField] private GameObject healthBarGO;
    5.     HealthBar healthBar;
    6.     TakeDamage takeDamage;
    7.  
    8.     private void Start() {
    9.         takeDamage = gameObject.AddComponent<TakeDamage>();
    10.         healthBar = healthBarGO.GetComponent<HealthBar>();
    11.     }
    12.     //if the player collides with enemy weak spot and can damage enemy
    13.     private void OnCollisionEnter2D(Collision2D collision) {
    14.         if (gameObject.CompareTag("Hazard") && collision.gameObject.CompareTag("Player")) {
    15.             takeDamage.EnemyTakeDamage(damageAmount);
    16.             healthBar.SetHealth(damageAmount);
    17.         }
    18.     }
    19. }
    If you have any tips on componentizing my scripts, I'm all ears.
     
  2. mopthrow

    mopthrow

    Joined:
    May 8, 2020
    Posts:
    348
    Hi,

    In TakeDamageOnCollision on line 16 you seem to be setting the healthbar's health to the damageAmount. I wonder if you should be calling something like a healthBar.SubtractHealth(damageAmount) because right now you're setting the health bar to 1 if the damage amount is 1.

    In addition, instead of instructing the health and healthbar to take damage seperately which can cause these kinds of desync issues, tie your healthbar to your health component, so when your health falls, your healthbar hears about it.

    You could for example raise an event in health component that the healthbar is subscribed to and send through the new health value. If you're not familiar with events you need a quick fix you could just send the new health value from the health component to the healthbar directly.