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;
}
}
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.
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.