Invoke () Working like InvokeRepeating ()
I am calling this invoke function after my player dies. I want him to respawn with a delay. It does get called after a five second delay, but then it gets called for five seconds as well and my player is stuck in his position for five seconds. Any help is greatly appreciated. :)
using UnityEngine;
using System.Collections;
public class Player_Death : MonoBehaviour {
private GameObject spawnPoint;
public Vector3 startPos;
public Transform armature;
public GameObject lowestLevel;
public bool dead = false;
private bool callRespawn;
public GameObject center;
// Use this for initialization
void Start () {
spawnPoint = GameObject.Find ("SpawnPoint");
startPos = spawnPoint.transform.position;
startPos.y += 1f;
if (armature != null) {
foreach (Transform child in armature) {
child.position = startPos;
}
}
callRespawn = true;
}
// Update is called once per frame
void Update () {
if (center.transform.position.y <= lowestLevel.transform.position.y) {
dead = true;
}
if (dead == true && armature != null) {
Invoke ("Respawn", 5f);
} else if (dead == true && armature == null) {
transform.position = startPos;
transform.root.GetComponent <Player_Health> ().health = 100f;
dead = false;
}
print (dead);
}
private void Respawn () {
print ("here " + 1 + Time.time);
foreach (Transform child in armature) {
child.GetComponent<Rigidbody> ().velocity = Vector3.zero;
child.position = startPos;
child.GetComponent<Rigidbody> ().isKinematic = false;
}
transform.root.GetComponent <Player_Health> ().health = 100f;
dead = false;
}
}
Answer by tanoshimi · Jun 24, 2016 at 07:28 PM
That's because, as your own comment states // Update is called once per frame
. So, after your player dies, you're calling a new Invoke() every frame until they respawn. It's only after 5 seconds, when the Respawn function first runs, that you set dead = false
and stop calling Invoke, but by then you've got 5 seconds worth of queued calls to get through - which is when your character freezes.
The solution would be to set
if (dead == true && armature != null) {
Invoke ("Respawn", 5f);
dead = false;
}
Or perhaps add a three-way state of "dead", "alive", "waitingToRespawn" or something like that.
Answer by Dave-Carlile · Jun 24, 2016 at 07:23 PM
if (dead == true && armature != null) {
Invoke ("Respawn", 5f);
That code is getting executed every frame, so you're calling Invoke over and over while those conditions are true. You need something to indicate that you've already invoked the respawn and add that to your if
condition to make sure it doesn't keep calling Invoke
.
Another way to deal with this sort of things is to set up a simple state machine using an enum
and switch
statement.
enum State { Running, Dead, WaitForRespawn, Respawn }
State state = State.Running;
....
void Update()
{
switch (state)
{
case State.Running:
DoRunningStuff();
if (center.transform.position.y <= lowestLevel.transform.position.y)
{
state = State.Dead;
}
break;
case State.Dead:
Invoke("Respawn", 5.0f);
state = State.WaitForRespawn;
break;
case State.WaitForRespawn:
// don't really do anything, or show a countdown, whatever
break;
case State.Respawn:
// do respawn stuff
// change state back to running
state = State.Running;
break;
}
}
void Respawn()
{
...
state = State.Respawn;
}
That doesn't cover everything you have in your example but it gets the point across. This sort of thing can often be more clear than checking a bunch of different variables to decide what to do.
Thanks for the examples of enum and switch statements. I am going to start using some of those more often. :)
Your answer
Follow this Question
Related Questions
How to change the bullet fire rate in C#? 1 Answer
Simple timer using InvokeRepeating 2 Answers
why won't an invokerepeating cancel? 1 Answer
How to subtract live when a game object destroy itself? 0 Answers
(SOLVED) Destroy(gameObject) doesn't destroy the gameObject, only disables behaviours. 0 Answers