0
\$\begingroup\$

I am new to making games with Unity.

I am trying to damage the enemy. So far, the damage works. The problem is it will repeat it until the enemy is dead, but I want it to damage the enemy only once.

void Update()
{ 
    if(Input.GetMouseButton(0) && !isCooldown){
        StartCoroutine(Cooldown());
        Attack();                                                       //ATTACK
    }
}

private void Attack() {
    anim.SetTrigger("attack");

    Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);

    foreach(Collider2D enemy in hitEnemies)
    {
        Enemy.GetComponent<EnemyHP>().TakeDamageEnemy(damage);
        Debug.Log("DamageENEMYYYYYYY");
    }
}
  • `Damage| is a public float with a value of 1.

  • the EnemyHP component has code to remove hit points corresponding to the damage dealt.

I've tested the code out with a Debug.Log and it does indeed remove the HP corresponding to the amount of damage. But it repeats the TakeDamageEnemy function.

The total hp = 3, so it repeats the code 3 times (the console shows the log 3 times).

How can I change it so it will only play it once?

\$\endgroup\$
4
  • 3
    \$\begingroup\$ If you are posting code, post all relevant code. The Coroutine Cooldown is missing for example. \$\endgroup\$
    – Zibelas
    Sep 26, 2022 at 17:26
  • 2
    \$\begingroup\$ What is Enemy? How many enemies are there, and how many enemies does a single attack hit? \$\endgroup\$
    – Vaillancourt
    Sep 26, 2022 at 17:29
  • 2
    \$\begingroup\$ I would suspect the spelling mistake as well since your variables are case sensitive. That means enemy in your foreach is not the same as Enemy \$\endgroup\$
    – Zibelas
    Sep 26, 2022 at 17:30
  • 1
    \$\begingroup\$ It seems to me that in the code Enemy.GetComponent<EnemyHP>().TakeDamageEnemy(damage); you actually intend to write enemy.GetComponent<EnemyHP>().TakeDamageEnemy(damage);, enemy with a lowercase e, but there may be something else at play here. \$\endgroup\$
    – Vaillancourt
    Sep 26, 2022 at 17:31

1 Answer 1

1
\$\begingroup\$

The total hp = 3, so it repeats the code 3 times (the console shows the log 3 times).

It seems like you've misinterpreted how the code works. There's nothing in the code that you've shared that would repeat based on the amount of HP that the enemy has. However, your code will repeat the attack each frame that the mouse is held down.

The code you've shared finds all colliders in a circular area, gets the EnemyHP component from each collider, and applies damage to each. If the message "DamageENEMYYYYYYY" appears in the console 3 times, that may mean that Physics.OverlapCircleAll() found 3 different enemies (or one enemy with multiple colliders). You can make this more obvious by including information about the enemy in your console output:

foreach(Collider2D enemy in hitEnemies)
{
    Enemy.GetComponent<EnemyHP>().TakeDamageEnemy(damage);
    Debug.Log($"Apply {damage} damage to {enemy}", enemy);
}

Here, we pass an interpolated string to Debug.Log(); within the interpolated string, we can include variables within braces, e.g. {damage} will output the value of the damage variable.

Notice that I included a second argument to Debug.Log(), the enemy variable. The second argument is called the "context". If the value we pass for the context is a GameObject or component, clicking on the log message in the Unity Editor will select that GameObject/component. This makes it much easier to quickly find the object that a log message is related to. In this case, if you click on the log message that says "Apply [...] damage to [...]", it will select the enemy that the damage was applied to.

Your current code has a design flaw - it will throw an error if there are any colliders in the circular area that do not have the EnemyHP component. Your code should look like this:

foreach(Collider2D collider in hitEnemies)
{
    var enemy = collider.GetComponent<EnemyHP>();
    //this prevents an error if the collider doesn't have the EnemyHP component
    if (enemy != null) {
        enemy.TakeDamageEnemy(damage);
        Debug.Log($"Apply {damage} damage to {enemy}", enemy);
    }
}

You should also consider changing your Update() function. Right now, you're using GetMouseButton(), which will repeat each frame that the mouse is held down. The code you shared doesn't have a fully implemented cooldown, so Attack() will get called every frame until you release the mouse. It's difficult to release the mouse after only one frame, so it's likely that you're initiating multiple attacks each time you click.

If you use GetMouseButtonDown() instead, it will only attack on the frame that the user pressed down the button, and won't keep attacking every frame that the button is held down. Once you've implemented the cooldown, you can go back to GetMouseButton() if you prefer the attack to automatically repeat after the cooldown if the mouse button is held down.

void Update()
{ 
    //use GetMouseButtonDown instead of GetMouseButton() so the damage
    //doesn't repeat each frame
    if(Input.GetMouseButtonDown(0) && !isCooldown){
        StartCoroutine(Cooldown());
        Attack();                                                       //ATTACK
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ While most of it is true, gets the EnemyHP component from each collider, is supposed to happen but OP has a spelling mistake in the posted code with a capital E for enemy. \$\endgroup\$
    – Zibelas
    Sep 27, 2022 at 7:29
  • \$\begingroup\$ @Zibelas I'm assuming that was just a transcription error (assuming he re-typed his code here rather than pasting it). He'd most likely be describing a different issue (such as a compiler error, or damage being applied to the wrong enemy) if he used the wrong capitalization in the original code. \$\endgroup\$
    – Kevin
    Sep 29, 2022 at 1:42
  • \$\begingroup\$ I'd recommend defaulting to "they" rather than "he" in cases when the gender of a new poster is not known. \$\endgroup\$
    – DMGregory
    Sep 29, 2022 at 2:08
  • \$\begingroup\$ OP wrote the code was tested with Debug.Log and we do not see how the actual enemy gets removed in the end. It might that there is a public Gameobject Enemy that is used for spawning, who knows. The formatting of code is odd enough to indicate it is copy pasted (//ATTACK floating at the right). I'm rather pointing the most obvious error out to exclude chasing shadows. \$\endgroup\$
    – Zibelas
    Sep 29, 2022 at 8:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .