Reputation: 105
I am trying to make the player hit the knife the enemy in front of him, but i only want to knife one enemy at once. The problem is, when the OnTriggerStay2D is called, every enemy that is in range of the box collider of the knife receives damage, when I want only one to receive damage. This is my script:
public float timeBetweenKnifes = 2;
public float timeSinceLastKnife = 0;
public int knifeDamage = 1;
[HideInInspector] public GameObject player;
void OnTriggerStay2D(Collider2D collision)
{
timeSinceLastKnife = timeSinceLastKnife + Time.deltaTime;
if(collision.gameObject.TryGetComponent<ZombieScript>(out ZombieScript enemyComponent) && Input.GetKey(KeyCode.E) && timeSinceLastKnife >= timeBetweenKnifes)
{
enemyComponent.TakeDamage(knifeDamage);
player = GameObject.FindGameObjectWithTag("Player");
player.GetComponent<PlayerScript>().money = player.GetComponent<PlayerScript>().money + 1;
timeSinceLastKnife = 0;
}
}
Upvotes: 0
Views: 55
Reputation: 90813
You do only attack one target call of the function OnTriggerToStay2D
!
What rather happens is that OnTriggerToStay2D
is called once for each overlapping object in the same frame!
You could simply have a flag
private bool alreadyCausedDamageThisFrame;
// to also prevent you timer to run faster for multiple collisions
// instead rather simply compare to a previous time rather than using a timer
private float lastKnifeTime;
void Start()
{
// to allow immediate attack the first time
lastKnifeTime = -timeBetweenKnifes;
}
private void FixedUpdate()
{
// at the beginning of each physics frame reset the flag
alreadyCausedDamageThisFrame = false;
}
void OnTriggerStay2D(Collider2D collision)
{
// if already caused damage this frame -> ignore
if(alreadyCausedDamageThisFrame) return;
// without timer directly compare to previous damage time
// if not enough time has passed -> ignore
if(Time.time - lastKnifeTime < timeBetweenKnifes) return;
// check input
// if key not pressed -> ignore
if(!Input.GetKey(KeyCode.E)) return;
// update time
// where exactly you do this depends a bit on your desired behavior
// keep it here if you want to allow to hit nothing and then have to wait for the cooldown
lastKnifeTime = Time.time;
// check/get component
// if not colliding with ZombieScript -> ignore
if(!collision.TryGetComponent<ZombieScript>(out var enemyComponent)) return;
enemyComponent.TakeDamage(knifeDamage);
var player = FindAnyObjectByType<PlayerScript>();
player.money += 1;
// set the flag to block any other OnTriggerStay2D call for this frame
// ensures you can ever only hit one single enemy in this frame
alreadyCausedDamageThisFrame = true;
// if you rather only want a cooldown after you actually hit an enemy rather move the
//lastKnifeTime = Time.time;
// down here
}
Upvotes: 0