- Home /
Wait in seconds before damaging the player again
Title says it all, basically I have a problem where my script damage the player in every second, I want to tell the script that it should be waiting like 5 seconds before damaging again.`{
public int Pain = 1;
void Start()
{
}
void OnTriggerStay (Collider other) { {
if (other.gameObject.tag == "Player")
{
StartCoroutine(CountDown());
Vector3 damageDirection = other.transform.position - transform.position;
damageDirection = damageDirection.normalized;
FindObjectOfType<PlayerHealth>().DamagePlayer(Pain, damageDirection);
}
}
}
IEnumerator CountDown()
{
print(Time.time);
yield return new WaitForSeconds(1000);
print(Time.time);
}
} `
As @TreyH said you don't need a coroutine to do this, I also suggest to store in a var the PlayerHealth
script, to don't call the FindObjectOfType each time apply damage
PlayerHealth healthScript;
void Start(){
healthScript = FindObjectOfType<PlayerHealth>();
}
whatever if you still want to use coroutines you have to manage it, you are calling one different on each OnTriggerStay
this (by default) is activated each 0.2 seconds... yes, very low for a bullet but ok by static acid/radiation...
Coroutine damager;
Vector3 damageDirection = Vector3.zero;
void OnTriggerStay (Collider other) {
if (other.gameObject.tag == "Player")
{
Vector3 damageDirection = other.transform.position - transform.position;
damageDirection = damageDirection.normalized;
//check if you already started the contact before, otherwise start
if (!damager)
StartCoroutine(CountDown());
}
}
IEnumerator CountDown()
{
print(Time.time);
//apply damage inside the coroutine
while (true){
healthScript.DamagePlayer(Pain, damageDirection);
yield return new WaitForSeconds(1000);
}
print(Time.time);
}
if you want the script apply a bit more of time damage after contact replace the while(true)
by a for loop, on the other hand. if you want to stop imediately the contact ends stop it with OnTriggerExit
void OnTriggerExit (Collider other) {
StopCoroutine(damager);
damager = null;
}
and last, if you want to apply acid by any of enemy or other players you will need to use the collider that you hit
void OnTriggerStay (Collider other) {
if (other.gameObject.tag == "Player")
{
healthScript = other.transform.GetComponent<PlayerHealth>();
...
IEnumerator CountDown()
{
while (true){
//check to be sure
if(healthScript)
healthScript.DamagePlayer(Pain, damageDirection);
...
Yeah, @DanProd if you're using some Unity function that starts with Find__, that's typically something that should either be cached in Start (or Awake) or just supplied in the Inspector.
Answer by TreyH · Feb 19, 2019 at 01:51 PM
I don't think you need a Coroutine at all:
private float hitLast = 0;
private float hitDelay = 5;
void OnTriggerStay (Collider other)
{
if (other.gameObject.tag == "Player")
{
if (Time.time - hitLast < hitDelay)
return;
Vector3 damageDirection = other.transform.position - transform.position;
damageDirection = damageDirection.normalized;
FindObjectOfType<PlayerHealth> ().DamagePlayer (Pain, damageDirection);
hitLast = Time.time;
}
}
that may be, but in his script he is waiting for 1000 seconds not 1!
"I want to tell the script that it should be waiting like 5 seconds before damaging again"
His post says that he wants to wait 5 seconds and seems to be confused about how to implement that. With that in $$anonymous$$d, the the ti$$anonymous$$g portion of his code should be disregarded, I think.
fair enough, comment is hear mainly because i don't think he understands what 1 second is by this post.
I prefer to do the operation once, and not everytime I check it.
if ( Time.time < nextHit )
return;
nextHit = Time.time + hitDelay;
They're equivalent, but whatever's more readable for the author / $$anonymous$$m is the ideal syntax yeah.
Answer by visca_c · Feb 19, 2019 at 03:01 PM
put the damage function in coroutine too, or else they would execute together without delay. Something like this: (Edit: if you want to use OnTriggerStay, you probably want to make sure you are not starting co-routine every frame when player is in trigger.)
bool coroutineRunning;
IEnumerator DmgAfterTime(float seconds)
{
coroutineRunning=true;
yield return new WaitForSeconds(seconds);
playerHealth.DamagePlayer (Pain, damageDirection);
coroutineRunning=false;
}
void OnTriggerStay(Collider other)
{
//if not running
if(!coroutineRunning)
StartCoroutine(DmgAfterTime(5));
}
Another way to run function after time is to use delegate in a cotoutine.
public delegate void RunFuncDelegate();
public IEnumerator RunFuncAfterTime(RunFuncDelegate Func, float time)
{
yield return new WaitForSecondsRealtime(time);
Func();
}
This way you can call any function after a delay.
StartCoroutine(RunFuncAfterTime(() => playerHealth.DamagePlayer (Pain, damageDirection), 5));
thats not the only problem, he is calling a new corroutine each OnTriggerStay
...
talking about call functions on delegate he ca also use built in InvokeRepeating
oh ya, missed the OnTriggerStay. Thanks for pointing out. I didn't know about Invoke before, just read about them now, why did Unity make Invoke takes in string as argument though? I can't mass-rename the function name that way.
I think it makes it dynamic or something i was reading?? *Do correct me if im wrong because i don't fully understand dynamics*What i understand is, with strings they can be passed through a server where i don't think you can be near as specific with int's if at all.
I was going to say this hours ago but wasn't 100% sure so i held off as i didn't know if it was necessary or not.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Error: CS0246 Can't access Player Health Script 1 Answer
Distribute terrain in zones 3 Answers
Cant Make C# Use waitforseconds Command 3 Answers
Pause a script completely 3 Answers