How to stop coroutines or functions

I’ve been working on this script for about 12 hours now and I haven’t made any progress. It’s for a whack-a-mole style game.

I have 3 movement types defined in 3 functions. They each reference the MoveObject script. MoleRetreat needs to be able to interrupt MoleAscend and MoleDescend when the script recognizes a hit on the mole. Any ideas?


var moveSpeed:int = 1;
var waitTime:float = 2.0;
var moleVisible:boolean = false;
var moleHit:boolean = false;
	
function OnBecameVisible() {
	moleVisible = true;
	print(gameObject.name + "is visible");
	StartCoroutine("AscendMole");
	yield WaitForSeconds (waitTime);
	StartCoroutine("DescendMole");
}
	
function AscendMole() {
	 yield MoveObject.use.Translation(transform, Vector3.up, moveSpeed, MoveType.Time);
}

function DescendMole() {
	 yield MoveObject.use.Translation(transform, -Vector3.up, moveSpeed, MoveType.Time);
	 bMoleVisible = false;
	 
	 // Adjust stats
	 GameStats.moleKillsInARow = 0;
	 print("Moles killed in a row: " + GameStats.moleKillsInARow);
	 Destroy (gameObject);
}

function MoleRetreat() {
	yield MoveObject.use.Translation(transform, -Vector3.up, .25, MoveType.Time);
	bMoleVisible = false;
	
	// Adjust stats
	GameStats.moleKillTotal = GameStats.moleKillTotal + 1;
	GameStats.moleKillsInARow = GameStats.moleKillsInARow +1;
	print("Moles killed: " + GameStats.moleKillTotal);
	print("Moles killed in a row: " + GameStats.moleKillsInARow);
	Destroy (gameObject);
}

function Update () {
	if (Input.GetKeyDown(KeyCode.KeypadEnter) && !moleHit) {
		// Recognize hit
		moleHit = true;
		
		// Adjust movement
		StopAllCoroutines();
		StartCoroutine("MoleRetreat");
	}
}

You're going about it the wrong way 'methinks' . Whack-a-mole is the classic example for a really small State Machine. I've got a 90% completed whack-a-something project over here. I'll try and strip it a bit

enum state_
    {
        resting,
        movingUp,
        movingDown,
        knocked,
        coolDown
    };
    state_ state;

IEnumerator MoveUp()
{
    state = state_.movingUp;

    float t = 0;
    while(t < 1&&state == state_.movingUp)
    {
        yield return null;
        t += Time.deltaTime / moveUpTime;
        TR.position = Vector3.Lerp(start, topPosition, t);
    }
    if(state == state_.movingUp)
    SetState(4);//coolDown
}

So our moving up coroutine only does things if it's in that state while(t < 1&&state == state_.movingUp). When you click it for example, the GameManager just calls SetState(3) and that does something like:

IEnumerator Knocked()
{
    state = state_.knocked;
    // insert various logic bits here
    float t = 0;
    while(t < 1)
    {
        yield return null;
        t += Time.deltaTime / 0.55f;
        TR.position = Vector3.Lerp(start, bottomPosition, t);
    }
    SetState(0);//rest
}

Notice this doesn't have a state condition, since we want the mole to not be interupted while going back into it's hole.

Ofcourse you'll be checking for specific states and things within the state switcher (SetState) itself, before starting a coroutine. For example:

if(state == state_.resting)   // make sure the mole is not doing anything important
    StartCoroutine(MoveUp()); // start moving
else                          // if mole busy
        GM.GetMole()          // get another random mole from the array

The Project

Eureka! Thanks azzogat! I was doing some experimenting with while loops yesterday but Unity kept crashing. I think I found something that works well.

I’m not sold on the state machine. I haven’t had any experience with enums yet, but after checking out your game, which is really cool, my plans are quite different. The code I have below is very different from what I was using (MoveObject script). If I keep going back to change things, I never get to move forward and learn from my mistakes. What I have now seems to work well so I’m going to stick with it.


var waitTime:float = 2.0;
var moleVisible:boolean = false;
var moleHit:boolean = false;
var moleKilledSpeed = 5;
var moleAliveSpeed = 1;
	
function OnBecameVisible() {

	moleVisible = true;
	StartCoroutine("MolePresents");
}
	
function MolePresents() {

	// Mole ascends
	while (transform.position.y < 1){
		transform.Translate(Vector3.up * Time.deltaTime * moleAliveSpeed);
		yield;
	}
	
	// Mole waits
	yield WaitForSeconds (waitTime);
	
	// Mole descends
	while (transform.position.y > 0) {
		transform.Translate(Vector3.down * Time.deltaTime * moleAliveSpeed);
		yield;
	
	}
	
	Destroy (gameObject);
	
}

function MoleKilled() {

	while (transform.position.y > 0) {
		transform.Translate(Vector3.down * Time.deltaTime * moleKilledSpeed);
		yield;
	}
	
	// Remove object
	bMoleVisible = false;
	Destroy (gameObject);
}

function Update () {
	
	if (Input.GetKeyDown(KeyCode.KeypadEnter) && !moleHit) {
		// Recognize hit
		moleHit = true;
		
		// Adjust movement
		StopCoroutine("MolePresents");
		StartCoroutine("MoleKilled");
	}
}