- Home /
Trouble with InvokeRepeating and Update
I'm trying to set up a gameplay feature in which enemies will increase in number depending on your score. This is what I have so far:
void Start()
{
//The point in which the new prefab will be spawned
GameObject[] objs = GameObject.FindGameObjectsWithTag("SpawnPoints") as GameObject[] ;
spawnPoints = new Vector3[objs.Length] ;
for(int i = 0 ; i < objs.Length ; i++)
{
spawnPoints[i] = objs[i].transform.position ;
}
endOfArray = spawnPoints.Length;
InvokeRepeating ("Spawn", timeToBegin, spawnTime);
}
void Update()
{
if(accelShotHS.score == 5)
{
spawnEnemyWaveOne ();
}
else if(accelShotHS.score == 15)
{
spawnEnemyWaveTwo ();
}
//etc etc...
}
void Spawn()
{
Instantiate(spawnableObject,spawnPoints[Random.Range(0,endOfArray)],Quaternion.identity);
}
void spawnEnemyWaveOne()
{
if(hasSpawned == false)
{
CancelInvoke ();
spawnTime = 4.0f;
InvokeRepeating ("Spawn", timeToBegin, spawnTime);
Debug.Log ("Wave 1");
hasSpawned = true;
}
}
void spawnEnemyWaveTwo()
{
if(hasSpawned == false)
{
CancelInvoke ();
spawnTime = 3.0f;
InvokeRepeating ("Spawn", timeToBegin, spawnTime);
Debug.Log ("Wave 2");
hasSpawned = true;
}
}
So I want the enemies to increase depending on the score and I have a Debug.Log() in place that tells me which wave it's in, it starts off fine, it goes to wave one, but it never leaves that wave. When i get passed 15, it stays in the same wave.
Anyone know why? Thanks in advance
Answer by robertbu · Aug 13, 2014 at 06:59 PM
You have a sure problem, and a couple of other things that are of concern. First this logic:
if(accelShotHS.score == 5)
{
spawnEnemyWaveOne ();
}
else if(accelShotHS.score == 15)
{
spawnEnemyWaveTwo ();
}
We don't see if 'accelShotHS.score' ever reaches 15, but if it does, this code still would not work. When the value is 15, this line:
if(accelShotHS.score == 5)
...is still true. That means the 'else' clause would never get executed. Reverse the logic so you check for 15 first:
if(accelShotHS.score == 15)
{
spawnEnemyWaveOne ();
}
else if(accelShotHS.score == 5)
{
spawnEnemyWaveTwo ();
}
The first potential issue is that I see no code here that sets 'hasSpawned' to false, and you need it to be false for line 49 to be true and the second wave to begin.
The second potential issue (and I'm less sure of this one), but I believe there can be problems if you do a CancleInvoke() and an immediate InvokeRepeating(). If this is the case (or even if not), rewrite your InvokeRepeating() as a CoRoutine(). Replace your Spawn() method with:
IEnumerater Spawner() {
yield return new WaitForSeconds(startWait(timeToBegin);
while (true) {
Instantiate(spawnableObject,spawnPoints[Random.Range(0,endOfArray)],Quaternion.identity);
yield return new WaitForSeconds(spawnTime);
}
}
Replace the InvokeRepeating() in line 12 with:
StartCoroutine(Spawner());
Then changing 'spawnTime' will change the rate of spawning without stopping or starting anything.
Thanks for the help robertu, seems I'm doing a lot wrong :/ This works great, best get learning.
Answer by Kiwasi · Aug 13, 2014 at 07:18 PM
You could write this all in a coroutine. This format eliminates both your Update method and your SpawnWaveXXX methods
void Start (){
// Other stuff
StartCoroutine(SpawnTimer());
}
private IEnumerator SpawnTimer(){
while (accelShotHS.score <6){
Spawn();
yield return new WaitForSeconds(5);
}
while (accelShotHS.score <16){
Spawn();
yield return new WaitForSeconds(4);
}
while (true){
Spawn();
yield return new WaitForSeconds(3);
}
}
An alternate way to code the coroutine would be. With this code there is no need to stop the coroutine once in starts, just adjust spawnTime and the code will take care of the adjustment automatically.
private IEnumerator SpawnTimer(){
while (true){
Spawn();
yield return new WaitForSeconds(spawnTime);
}
}
Answer by mediumal · Aug 13, 2014 at 07:01 PM
I think it is because hasSpawned is never set to false again.
Also, you should protect against the case where you manage to score two points in one frame, causing your score to jump from 14 to 16 without ever hitting 15.