Problem with InvokeRepeating.

So, i’m trying to use InvokeRepeating to make a countdown, but it gets called a bunch of times, even using a bool just to make it run once as you can see on the debug it runs a million times. Any advice, i must be doing something wrong.

If you want to test it just attach it as it is and set time visible to 5 and hit points to 1 and respawn timer to 2. The rest is just interaction with other classes.

public class MoleScript : MonoBehaviour {

	//Public variables.
	public float timeVisible;
	public int currentHitPoints;
	public int pointsWorth;
	public int hitPoints;
	public bool retracting;
	public int respawnTimer;
	public bool respawnable;
	public bool happened;
	
	//Private variables.
	private float moleSpeed = 11;
	private Vector3 destination;
	private Vector3 origin;
	private bool alreadyScored;
	public float timeLeft;
	public bool killable;
	
	void Start () {
		destination = new Vector3(transform.position.x, transform.position.y+4, transform.position.z);
		origin = transform.position;
		RandomizeMole();
	}
	
	void Update () {
		
		if(!retracting) {
			Eject();
		} else {
			Retract();
		}
		
		if(timeLeft == 0) {
			alreadyScored = true;
			currentHitPoints = 0;
		}
		
		
		if(currentHitPoints > 0) {
			retracting = false;
			killable = true;
			alreadyScored = false;
		}
		if(currentHitPoints == 0) {
			retracting = true;
			killable = false;
			if(!alreadyScored) {
				PlayerScript.score += pointsWorth;
				alreadyScored = true;
				timeLeft = 0;
		    }
			StartCoroutine(RespawnTimer());
		}
		
		if(respawnable) {
			if(!happened){
				happened = true;
				RandomizeMole();
			}
		}
	}
	
	void subtractTimeVisible() {
		timeLeft--;
		Debug.Log("time left --");
		if(timeLeft <= 0) {
			CancelInvoke("subtractTimeVisible");
			Debug.Log("cancel invoke");
		}
	}
	
	IEnumerator RespawnTimer() {
		yield return new WaitForSeconds(respawnTimer);
		respawnable = true;
	}
	
	//Move the Mole up.
	void Eject() {
		transform.position = Vector3.MoveTowards(transform.position, destination, Time.deltaTime * moleSpeed);
	}
	
	//Returns to original position.
	void Retract() {
		transform.position = Vector3.MoveTowards(transform.position, origin, Time.deltaTime * moleSpeed);
	}
	
	void RandomizeMole() {
		if(respawnable) {
			currentHitPoints = hitPoints;
			timeLeft = timeVisible;
			respawnable = false;
			InvokeRepeating("subtractTimeVisible", 1, 1);
			Debug.Log("Invoke");
			happened = false;
		}
	}
}

yep. dont call it from update.

call it once from start

But i need it to happen when a set of conditions is met, i can’t call it only on start, should i change the invoke to a coroutine?

I changed the Invoke to a Coroutine, but now some bool variables are being changed on weird times, like respawnable and happened.
I really don’t know what to do from here.

using UnityEngine;
using System.Collections;

public class MoleScript : MonoBehaviour {

	//Public variables.
	public float timeVisible;
	public int currentHitPoints;
	public int pointsWorth;
	public int hitPoints;
	public bool retracting;
	public int respawnTimer;
	public bool respawnable;
	public bool happened;
	
	//Private variables.
	private float moleSpeed = 11;
	private Vector3 destination;
	private Vector3 origin;
	private bool alreadyScored;
	public float timeLeft;
	public bool killable;
	
	void Start () {
		destination = new Vector3(transform.position.x, transform.position.y+4, transform.position.z);
		origin = transform.position;
		RandomizeMole();
	}
	
	void Update () {
		
		if(!retracting) {
			Eject();
		} else {
			Retract();
		}
		
		if(timeLeft == 0) {
			alreadyScored = true;
			currentHitPoints = 0;
		}
		
		
		if(currentHitPoints > 0) {
			retracting = false;
			killable = true;
			alreadyScored = false;
		}
		
		if(respawnable) {
			if(!happened){
				happened = true;
				RandomizeMole();
				respawnable = false;
			}
		}
		
		if(currentHitPoints == 0) {
			retracting = true;
			killable = false;
			if(!alreadyScored) {
				PlayerScript.score += pointsWorth;
				alreadyScored = true;
				timeLeft = 0;
		    }
			StartCoroutine(RespawnTimer());
		}
	}
	
	IEnumerator subtractTimeVisible() {
		for (int i = 0; i < timeVisible; i++) {
			yield return new WaitForSeconds(1);
			timeLeft--;
		}
		happened = false;
		timeLeft = 0;
	}
	
	IEnumerator RespawnTimer() {
		yield return new WaitForSeconds(respawnTimer);
		respawnable = true;
	}
	
	//Move the Mole up.
	void Eject() {
		transform.position = Vector3.MoveTowards(transform.position, destination, Time.deltaTime * moleSpeed);
	}
	
	//Returns to original position.
	void Retract() {
		transform.position = Vector3.MoveTowards(transform.position, origin, Time.deltaTime * moleSpeed);
	}
	
	void RandomizeMole() {
		if(respawnable) {
			currentHitPoints = hitPoints;
			timeLeft = timeVisible;
			StartCoroutine(subtractTimeVisible());
			respawnable = false;

		}
		respawnable = false;
	}
}

Well the problem is that in your current code version the RespawnTimer() method is actually supposed to run every frame once the gameObject has 0 hitpoints.

What kind of boolean checks did you include so far? Those are not in the code you posted here.

Basically the main part to be adjusted can be updated like this, which should work:

if(currentHitPoints == 0) {

	retracting = true;

	killable = false;

	if(!alreadyScored) {

		PlayerScript.score += pointsWorth;

		alreadyScored = true;

		timeLeft = 0;

	}

	if (!waitingForRespawnTimer) {
		StartCoroutine(RespawnTimer());
	}
}

And

IEnumerator RespawnTimer() {
	waitingForRespawnTimer = true;
	
	yield return new WaitForSeconds(respawnTimer);

	respawnable = true;
	waitingForRespawnTimer = false;
}

Declare the bool waitingForRespawnTimer first, as usual.

You might also be better off not to perform all the logic within Update() based on bool flags, but you may use other functions to get stuff done.

For example: Move the “if (respawnable) …” part out of Update() and create a new function Respawn() which contains the code. Then in RespawnTimer() just call the Respawn() function just after the yield statement. Has the same effect yet it shrinks your update code, makes your code more managable, allows you to use the Respawn() method in other circumcanstances and is way easier to debug as stacktracing will give you more details.