- Home /
Press a key to damage all enemies tagged as Enemy separately
My player character has is a trigger and uses the below code to detect enemies
protected void OnTriggerEnter2D(Collider2D collision) { if (collision.gameObject.CompareTag("Enemy")) { enemyInRange = true; collision.gameObject.GetComponent().DepleteHealth(1); } }
This works fine when I move my player over the enemy multiple times it take 1 point of damage off them which is fine. But what I want is to only call that DepleteHealth() method when the player presses the E key instead. I tried to do it inside the update method but only works on one enemy, when you move your player over to enemy number 2 you get an error saying that the referenced object was destroyed which is correct because Enemy 1 was, my code cant register that the player is in front on Enemy 2 now.
I cant figure out how to kill enemy 1 then kill enemy 2 when I press the E key.
Answer by yummy81 · Jan 03, 2021 at 10:07 AM
I reproduced your problem. I created Player object with the Player script and a couple of enemies with the EnemyHealth script attached to each of them. Player script contains the list of enemies that are currently within the range of the collider. The list is static because each enemy has to remove itself from the list when destroyed. That takes into consideration the case when the enemy would be destroyed not by pressing E key, but somehow else. Hope that helps. Player script:
public class Player : MonoBehaviour
{
public int damage = 1;
public static List<EnemyHealth> enemiesInRange = new List<EnemyHealth>();
void Update()
{
if (Input.GetKeyDown(KeyCode.E))
for(int i = enemiesInRange.Count - 1; i >= 0; i--)
enemiesInRange[i].Deplete(damage);
}
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
var enemyHealth = collision.GetComponent<EnemyHealth>();
if (enemyHealth!=null && !enemiesInRange.Contains(enemyHealth))
enemiesInRange.Add(enemyHealth);
}
}
void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
var enemyHealth = collision.GetComponent<EnemyHealth>();
if (enemyHealth!=null && enemiesInRange.Contains(enemyHealth))
enemiesInRange.Remove(enemyHealth);
}
}
}
EnemyHealth script:
public class EnemyHealth : MonoBehaviour
{
public int health;
int maxHealth = 3;
void Awake()
{
health = maxHealth;
}
public void Deplete(int damage)
{
health -= damage;
if (health <= 0)
Destroy(gameObject);
}
void OnDestroy()
{
if (Player.enemiesInRange.Contains(this))
Player.enemiesInRange.Remove(this);
}
}
Thank you so much. This was exactly what I was looking for works perfectly now, I read people saying to use lists for this but I wasn't sure how to implement it into my game properly.
Thanks for taking the time to help :)
Answer by PilgrimFlowers · Jan 02, 2021 at 02:47 AM
A bit of a silly question, but I know I've made this mistake before: are both/all of your enemies marked with the tag "Enemy"? The other thing I would consider is using the method OnTriggerStay2D which checks continually while the trigger is active. So:
private void OnTriggerStay2D(Collider2D collider)
{
if (collider.tag == "Enemy")
{
//Your damage function
}
}
What I also may suggest is switching it around. What I mean is give the enemy objects a trigger box collider and run the collider check from the enemy checking if the Player is in the collider instead of checking if the Enemy is in the Player's collider (which is what I think you're doing given that you're checking for tag "Enemy"??)
This is what I would do on my Enemies' collider checks. This checks first that an object (specifically labelled "Player" is inside the collider, and for every frame that the object is within the collider, then while that is true, checks if the E key has been pressed, and then does your damage, but only once per key press. This will apply for all colliders that the Player is within as well (allowing to damage multiple enemies at once)
private void OnTriggerStay2D(Collider2D collider) { if (collider.tag == "Player") { if(Input.GetKeyDown(KeyCode.E) { //Your damage function } } }
Answer by TheIrishKraken · Jan 02, 2021 at 03:11 AM
Hello
Thanks for the response. Yes both are tagged with Enemy. I have tried switching around already but no good.
You cant call Input.GetKeyDown inside OnTriggerStay or Enter, must be called in the Update() method.
This should seem easy in theory but I cant wrap my head around what the solution might be. Once I kill enemy 1 Unity still thinks I am trying to kill enemy 1 when I am trying to kill enemy 2.
This code below works perfectly when I touch my player off both enemies one after another, but I need to alter it to only kill when I press the E key.
public KeyCode E; //select key "E" in inspector
bool isEpressed = false;
void update()
{
if(Input.GetKeyDown(E);
isEpressed = true;
}
//write this is onTriggerEnter2d
if(isEpressed)
{
//ur above code
}
Thanks for the reply but that approach didn't work. if(isEpressed) gets completely ignored inside the OnTriggerEnter2D() method. $$anonymous$$aybe you cant do any other checks inside that method except checking for collision.
Answer by Llama_w_2Ls · Jan 02, 2021 at 08:00 AM
You should do a raycast in the Update() to see which enemy you're closest to, by getting the distance from each enemy to the player and sorting it. This could be done every time you press the 'E' key, and if the distance between an enemy and the player is very small, you're colliding. @TheIrishKraken
Your answer
Follow this Question
Related Questions
trigger problem 0 Answers
2D Character slows down in a trigger 2 Answers
Trigger in child - boxcollider2d without trigger on parent issues. 0 Answers