(Closed)My Android game freezes after 7-12 minutes because of this code

So I’ve been experiencing freezes on my Android game, only on my device not in the editor.

The game just freezes. The background music continues to play, some sound effects like rain and thunder continue to play but game itself looks like an image; it’s just frozen.

I’ve successfully been able to pinpoint what method is causing it but I can’t figure out why. On a more interesting note this only started happening when I upgraded to Unity 4.2. With no modification this worked without a problem on 4.1.

[NOTE]

I also want to point out that I have script debugging on and I’m using LogCat to monitor any errors my phone spits out. When the freezing happens there is NOTHING printed out. According to Unity/my device there are no errors.

This is the code that causes the game to freeze after 7-12 minutes of playing:

public IEnumerator MusicRoutine(){
		while(true){
			if(playingMusic){
				musicSource.Stop();
				if(shuffle){
					int randomNumber = Random.Range(0, (musicList.Length - 1));
					lookingForASong = true;
					while(lookingForASong){
						for(int i = 0;i < whatSongsHaveWePlayedShuffle.Length;i++){
							if(randomNumber == whatSongsHaveWePlayedShuffle*){*
  •  						i = 100;*
    
  •  						tempbool = true;*
    
  •  					}*
    
  •  					if(tempbool == false){*
    
  •  						nothingMatched = true;*
    
  •  					}else{*
    
  •  						nothingMatched = false;*
    
  •  						tempbool = false;	*
    
  •  					}*
    
  •  				}*
    
  •  				if(nothingMatched){*
    
  •  					lookingForASong = false;*
    
  •  					nothingMatched = false;*
    
  •  					musicSource.clip = null;*
    
  •  					yield return null;*
    
  •  					yield return null;*
    
  •  					musicSource.clip = musicList[randomNumber];*
    
  •  					yield return null;*
    
  •  					yield return null;*
    
  •  					whatSongsHaveWePlayedShuffle[tempIndexNumber] = randomNumber;*
    
  •  					tempIndexNumber++;*
    
  •  					if(tempIndexNumber >= musicList.Length){*
    
  •  						tempIndexNumber = 0;*
    
  •  						resetShuffleArrayForWhatSongsHaveBeenPlayed();*
    
  •  					}*
    
  •  				}else{*
    
  •  					randomNumber = Random.Range(0, (musicList.Length - 1));*
    
  •  				}*
    
  •  			}*
    
  •  		}*
    
  •  		else{*
    
  •  			musicSource.clip = null;*
    
  •  			yield return null;*
    
  •  			yield return null;*
    
  •  			musicSource.clip=musicList[currentTrackID];*
    
  •  			yield return null;*
    
  •  			yield return null;*
    
  •  			currentTrackID+=1;*
    
  •  			if(currentTrackID == musicList.Length) {*
    
  •  				currentTrackID=0;*
    
  •  			}*
    
  •  		}*
    
  •  		yield return new WaitForSeconds(0.5f);*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return new WaitForSeconds(1f);*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		//we must have a hand full of delays to make sure the clip is playable*
    
  •  		if(musicSource.clip.isReadyToPlay){ //im not exactly sure how this check works so we'll keep the delays*
    
  •  			musicSource.Play(); //start playing*
    
  •  			yield return null;*
    
  •  			yield return new WaitForSeconds(musicSource.clip.length + 2.3f);*
    
  •  		}else{*
    
  •  			//im not sure why we wouldn't be ready but if we still aren't ready lets wait*
    
  •  			yield return null;*
    
  •  			yield return new WaitForSeconds(3f);*
    
  •  			yield return null;*
    
  •  			if(musicSource.clip.isReadyToPlay){ //one more check for shiggles*
    
  •  				musicSource.Play(); //start playing*
    
  •  				yield return null;*
    
  •  				yield return new WaitForSeconds(musicSource.clip.length + 2.3f);*
    
  •  			}else{*
    
  •  				//it's still not ready so something is wrong, lets break out;*
    
  •  				break;*
    
  •  			}*
    
  •  		}*
    
  •  		yield return null;*
    
  •  	}else{*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return new WaitForSeconds(2f);*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  		yield return null;*
    
  •  	}*
    
  •  }*
    
  • }*
    It does not matter if shuffle is true or false.
    On a more interesting note if I set playingMusic to false so that it doesn’t actually execute any of the music playing it does NOT freeze. This value was set to false at STARTUP before it was ever able to execute. (It’s a PlayerPref).
    Can anyone think of why this is causing my game to freeze?

Thanks

Let me sum up your script with one word: horrible!

Some more details:

  • It seems you’re missing some fundamental keywords like “break”. Your i=100 “solution” is prone to error and makes it really hard to understand your code.
  • Random.Range comes in two versions, one that takes floats and return floats and one that takes ints and return an int. You use the int version and the “max” parameter is exclusive, so substracting 1 from Length will skip the last one.
  • Your way of selecting a random song is the most inefficient and your actual problem.

Your “while(lookingForASong)” loop won’t exit once each possible song has been played. Since you don’t have a yield inside the loop in this case you’re caught in an infinite loop. Since you never clear / resets the members of your “whatSongsHaveWePlayedShuffle” array once each song is in that array, none can be replayed. Without a yield you will never exit this loop ==> crash

You should split this code into some meaningful functions since this is a mess. Something like this:

// C#
private int lastPlayedSong = -1;

List<int> GenerateShuffleList(int aCount, int aMakeThisLast)
{
    var tmp = new List<int>(aCount);
    for (int i = 0; i < aCount; i++)
        if (i != aMakeThisLast)
            tmp.Add(i);
    var result = new List<int>(aCount);
    while(tmp.Count > 0)
    {
        int index = Random.Range(0, tmp.Count);
        result.Add(tmp[index]);
        tmp.RemoveAt(index);
    }
    if (aMakeThisLast>=0 && aMakeThisLast < aCount)
        result.Add(aMakeThisLast);
    return result;
}

IEnumerator PlaySong(int aIndex)
{
    aIndex = aIndex % musicList.Length;
    lastPlayedSong = aIndex;
    musicSource.Stop();
    musicSource.clip = musicList[aIndex];
    musicSource.Play();
    yield return new WaitForSeconds(musicList[aIndex].Length + 0.5f);
}

public IEnumerator MusicRoutine()
{
    var shuffleList = GenerateShuffleList(musicList.Length, -1);
    while(true)
    {
        if(playingMusic)
        {
            if(shuffle)
            {
                if (shuffleList.Count == 0)
                {
                    shuffleList = GenerateShuffleList(musicList.Length, lastPlayedSong);
                }
                int index = shuffleList[0];
                shuffleList.RemoveAt(0);
                yield return StartCoroutine(PlaySong(index));
            }
            else
            {
                yield return StartCoroutine(PlaySong(lastPlayedSong + 1));
            }
        }
        else
        {
            yield return null;
        }
    }
}

Note: I’ve written this from scratch an haven’t tested it, so there might be some syntax errors :wink: You need to add a “using System.Collections.Generic;” at the top.

I’m going to point out that having yield return null; over and over again probably isn’t helping.

So I figured it out due to a comment below from Bunney83. He stated that Random.Range when using it to return ints it does not include the last number.

So on line 6 and 38 I do:

randomNumber = Random.Range(0, (musicList.Length - 1));

Because of this the last index on the array never gets put as a random number causing my for loop to go into a infinite loop once all songs have been played but the last one. I removed the - 1 and it doesn’t freeze.

This doesn’t explain why it still froze when shuffle was false. Some more testing will be required…