How to avoid frequent INSTANTIATING DESTROYING objects (=low FPS), in an iOS game?

Discussion in 'iOS Development' started by schwertfisch, Jan 20, 2011.

  1. schwertfisch

    schwertfisch

    New Member

    Joined:
    Sep 7, 2010
    Messages:
    108
    I’m making an iOS board game.
    In this game, collectibles (I’ve got 4 different types of them) are instantiated at random positions every 4” and using my character (that moves on the board) I collect ( destroy) the collectibles.

    I was having a HUGE framerate problem, caused mainly by the way I managed the board (I was checking which board tiles are empty and instantiating a collectible randomly on one of them, using GameObject.FindWithTag...). After getting lots and lots of help by the community, I corrected the way these things are managed, but I'm still having low framerate (better than before, but still unacceptable).

    I just learned that this, is almost definitely caused, by the frequent instantiating and destroying of objects, which kills the iphone performance. What's more, this is an "endless mode" type of game, where one can play for many many minutes in this same level and after say 10' there can be 100 collectibles that have been well...collected (thus destroyed). After about a minute of playing, the game is almost frozen... Oh and of course, some sounds don't play (because of GC I suppose?)

    The board has 48 tiles and at maximum it can have about 10-15 collectibles of each type on-screen (due to the fact that what kind of collectible will be instantiated is random and is done from a built-in Array with these 4 objects).

    What would be a good approach to doing what I want, without instantiating/destroying the collectibles?

    I’ve thought of creating 15 collectibles of each type off camera at function Start and having them moved (instantly) at random tiles every 4’’ and being moved off camera (instantly again) whenever my character collects them, but haven’t figured out how to select a random collectible between the ones that are still off board.
    Last edited: Jan 20, 2011
  2. greensquidsolutions

    greensquidsolutions

    New Member

    Joined:
    Nov 2, 2009
    Messages:
    47
    Hi,

    I was thinking of doing something like this for my game, setting the mesh renderer to false for anything which isn't on the screen and when it is, then turn it on. It's just an idea I had for my project so it probably won't work, but worth a shot if nothing else is working.

    Thanks

    Dan.
  3. Adam Buckner

    Adam Buckner

    Unity Technologies

    Joined:
    Jun 27, 2007
    Messages:
    3,418
    You need pooling.

    You need an array of objects, even more objects than can be used, and set them to inactive. (This is good to do with bullets, aliens, asteroids, etc..)

    When you place one, iterate thru the array and set the first object you find that is inactive to active, place it in the game, and break your iteration loop. When an object is collected, account for it and increment the collection counter and then set it to inactive and it's back in your pool to use again. You can choose to move these to an offscreen location or not. Heck - they're deactivated.

    If you can't imagine how many of each type (say a max of a total of 100 objects, but they could be of 4 types, so you'd need 100*4=400 objects to be safe...), then could you make an object that could appear as any of the 4? Take it out of the pool, set it's type. (CollectionType = Cherry), activate it, place it... etc.

    Make sense?
  4. schwertfisch

    schwertfisch

    New Member

    Joined:
    Sep 7, 2010
    Messages:
    108
    I'll try to do something according to your suggestion. Thanks Little Angel.

    @greensquidsolutions: thank you Dan, I guess activate/deactivate as LittleAngel suggests, sounds better.
  5. greensquidsolutions

    greensquidsolutions

    New Member

    Joined:
    Nov 2, 2009
    Messages:
    47
    no worries, it gives me an idea on how to approach it when I come to do something like this :)

    Thanks

    Dan.
  6. schwertfisch

    schwertfisch

    New Member

    Joined:
    Sep 7, 2010
    Messages:
    108
    I use the following script, attached to an empty game object:

    var popSoundAtSpawn: GameObject; //the sound that plays when a token is spawned
    var spawnObjects : GameObject[];// this is the Array comprised of tokens that will be randomly spawned
    var tilesArray : GameObject[];// this is the Array comprised of all squares of the board
    var tokensPool : GameObject[];//this is the Array comprised of 15 tokens that at maximum will be on board at the same time
    var spawningRate: float= 3.3; // every spawningRate seconds, one token will be moved on board
    var delayBeforeSpawningBegins: float =2;// when the level begins, it will wait 2" before it starts spawning tokens
    var emptySquares: int;
    var spawnSuccessful: boolean;
    var tokensSpawned: int=0;

    function Awake(){
    InvokeRepeating("Spawn", delayBeforeSpawningBegins, spawningRate); // make spawn a token every "spawningRate" seconds
    }

    function Spawn(){
    randomTileNumber = Random.Range(0,tilesArray.length); //this will choose a random tile of the board
    randomTokenNumber = Random.Range(0,tokensPool.length); // this will choose a random token from the tokens Pool
    var spawnSuccessful = false;
    while (spawnSuccessful == false (tokensSpawned-characterScript.tokensSwallowed)<47)) {// this makes sure that the tokens spawned minus the ones swallowed by my character are less or equal to my available board tiles, which are 48 (in total) minus 1 that my character occupies = 47. So the while's escape condition, will be met when the board is full of tokens
    var placeToSpawn: GameObject = tilesArray[randomTileNumber]; //the position of one of the randomly selected board tiles. In that position will the token be spawned
    var spawnedToken: GameObject = tokensPool[randomTokenNumber]; // this will pick randomly, one of the tokensPool Array's contents
    if (placeToSpawn.tag == "EmptyTile" spawnedToken.active == false){ // this checks if the selected tile is empty and if the selected token is one of the deactivated tokens that are still off-board and have not been moved on it.
    iTween.MoveTo(spawnedToken,{"x" : placeToSpawn.transform.position.x, "y" : 0, "z" : placeToSpawn.transform.position.z,"time":0}); //this will move the token instantly, on the randomly selected empty tile's position
    spawnedToken.active = true; //the token will be activated
    tokensSpawned ++; // the number of instantiated tokens will be increased
    Instantiate(popSoundAtSpawn); // the spawning "pop" sound will be played
    spawnSuccessful = true; // the while's escape condition will be met
    }
    }
    }




    What happens, is when I hit play, sometimes 5, sometimes 10 (at best) collectibles are activated and spawned in random positions (as expected) and Unity freezes. Am I getting into an infinite loop? Isn’t this script a good way to have the token prefbs spawned and removed from the board?
    Even if i simplify the "while" line like this:

    while (spawnSuccessful == false ) {

    I get the same freezing after 5-10 spawns problem. It seems like Unity freezes when it tries to randomly pick a token from the tokensPool, that has already been picked-spawned and is already on the board. I would expect it not to try to pick an already spawned token though, as I use:

    spawnedToken.active == false

    in the "if" statement.
    Last edited: Jan 23, 2011
  7. schwertfisch

    schwertfisch

    New Member

    Joined:
    Sep 7, 2010
    Messages:
    108
    Actually the problem was that I had:

    randomTileNumber = Random.Range(0,tilesArray.length); //this will choose a random tile of the board
    randomTokenNumber = Random.Range(0,tokensPool.length); // this will choose a random token from the tokens Pool

    out of the while loop.
    It caused the engine to occasionally try to pick a token that had already been picked and that hanged it.
    Putting them inside the "while" (thanks to Marowi's help here), solved the problem.
    Last edited: Jan 23, 2011