I just want confirm if I’m on the right track here (and the reason I’m putting this in the iPhone forum is specifically due to ensuring optimal performance of my scripts).
As I understand, allocating memory at run-time is a no-no; I want to have an endless stream of enemies let’s say, so am I correct in assuming that I want to have X number of enemy GO’s preallocated prior to instantiating them into the game world? In other words cycling a set of 10 in and out of existence as the player mows them down.
Allocate Memory on Startup
Instantiate Enemy
Gameplay Cycle
Destroy Object (enemy)
Instantiate New Enemy
Now if I’m wrong here, then please enlighten me as then I’m not sure how to handle this situation.
Yea I was going to go that route initially, but lets say for a moment that I wanted 10 of X enemy, then later on as the player gets to the end of a round, I want 6 of X enemy and 4 of the tougher Y enemy?
If I maintain the ‘set’ of enemies I cycle in and out, I’m stuck with just that set, unless you have a better, interim solution?
unless you use masses of memory, why not allocate pools of the maximum number of objects of the type you need.
if you know you will never need more then 10 X, 4 Y, 2 Z and 1 W at a time, there is no good reason to not precreate them as they will barely need more than a few kbytes
There are lots of ways to do something like that. You can make an EnemyManger class that has as a public variable maxEnemies and a prefab for the enemy type. As you get to the end of your level you can lower the maxEnemies to reduce the memory footprint by destroying unneeded enemies. You can then create a new EnemyManager with the stronger enemies and a maxEnemies of 4.
The EnemyManger class could be made fully generic so that you can use it in any future games that you make.
Well wait, dreamora/uprise, isn’t that what I’m asking in my initial post? Allocating the memory I WILL need and then instantiate the enemies as I need them, and of differing types as well, no?
Okay cool, and yes wrong terminology. I meant creating a GO variable that I would fill in with whichever enemy I needed.
Now as for instantiating/destroying…is that going to be a problem performance wise?
What I’m asking here is not if it will merely work, but if it is the better path to take to have the ‘endless wave’ of enemies gameplay and not hitch when new enemies need to exist.
Instantiating/destroying is very expensive on the iPhone. It is essentially alloc/deallocing the GameObjects when you can just make a Reset() function and reuse them.
Okay I’m confused…I thought what was expensive in THOSE situations was allocating the memory for them at runtime…if the memory is already allocated then why would those be a problem.
Then I ask again, what is the best way to approach this where I want to have not only a set amount of enemies, but the option to have ‘different’ enemies?
There is no concept of allocating memory in .NET. By Instantiating an object you are in effect allocating the resources necessary for that object. By destroying the object you are in essence deallocing the object. By constantly Instantiating then destroying objects you are allocing and deallocing memory constantly.
One possible solution:
Instantiate the maximum number of each of the different types of enemies that you will need (6 weak and 4 string, for example) at level start. Never destroy any of these. If you need to have an enemy be ‘killed’ in the game play the death animation, fade it out or whatever you will be doing then ‘reset’ the objects properties and reuse it.
In which way is mine different from yours. Its exactly the same. We both pool the max amount of required object instances of a given class for reuse through the level at the level startup.
As for alloc and dealloc: you are not deallocating anything normally out of the os sight. you hand the memory back to the pool
creating / destroying object is still a costly operation but nowhere as bad as alloc / dealloc against the OS.
I misread what you meant. I assumed you meant to instantiate a whole bunch of GO’s and then as they are killed Destroy them so that you are only Instantiating once but not reused.
var enemy1 : GameObject;
var enemy2 : GameObject;
var enemy3 : GameObject;
var enemy4 : GameObject;
var enemy5 : GameObject;
…
…and so on.
At runtime I decide which type of enemy I need (weak/strong/fast/slow/etc) at any given moment and instantiate the prefab and assign it to the next available var enemy.
This way I can fill those variables with ANY kind of enemy, not just a predefined set that I’m stuck with for that level.
…and the reason I need to destroy them is that I might need 10 grunts, then later on need 10 heavy gunners…I’m not going to keep 20 enemies in memory, but rather just replace those variables with heavy gunners now.
Just make a few ‘buckets’ of enemies at the start of the level:
Pseudo Code
weakGuysArray = new weakGuysArray[maxWeakGuys];
mediumGuysArray = new weakGuysArray[maxMediumWeakGuys];
strongGuysArray = new weakGuysArray[maxStrongGuys];
// Instantiate all your objects ahead of time
for( int i = 0; i < weakGuysArray.length; i++ )
{
weakGuysArray[i] = Instantiate( someWeakGuyPrefab );
weakGuysArray[i].active = false;
}
// Do that for mediumGuys and strongGuys
// ....later on at runtime....
GameObject newEnemy;
if( needWeakGuy )
{
newEnemy = weakGuysArray[currentWeakGuyIndex++];
// Some logic to wrap the current index properly
}
else if( needMediumGuy )
{
newEnemy = mediumGuysArray[currentMeduimGuyIndex++];
// Some logic to wrap the current index properly
}
newEnemy.active = true;
return newEnemy;
That is the basic idea. If you want to get fancy, you can make the ‘buckets’ resizable so that as your level progresses if you need more mediumGuys and less weakGuys you can just set a proper max*Guys and dynamically resize the array.
There are tons of ways to do this so you will have to decide based on your actual game and how many enemies of each type you will need at any one time.
For the very simple pseudo code it is just preallocation and reuse. As mentioned, that is a very quick and easy way to do things. If your game requires highly variable numbers of enemies, very tight memory constraints, etc you can go the slightly more complicated route and dynamically resize your array buckets’.
One simple example of this is some endless enemy game where the enemies get stronger as time goes on. You could start with maxWeakEnemies = 10 and maxMediumEnemies = 0. After some event (20 weak enemies killed, 2 minutes passed, etc) reduce the maxWeakEnemies size (dynamically reduce the actual GameObject array) and increase the maxMediumEnemies array (dynamically increase the medium enemy array and instantiate as many new GameObjects as needed).
This is just fine and dandy. It’s much faster processing wise to just make a big pool of guys to start with upon level load and recycle them than it is to constantly create and destroy objects. GameObjects take up such a trivial amount of memory that you’d have to have a pretty ludicrous number of them before it started to make any kind of noticeable impact. I almost never use Instantiate on iPhone, only when I don’t want to go through the hassle of setting up a pool of objects for one-off situations.
In my games I always just use a pool of junk (bad guys, special effects, etc.) that are hidden off screen somewhere, and I keep references to these things’ Transforms, Scripts, and/or Animations in arrays, pulling them on screen at desired positions when needed.
Maybe we’re confusing two separate things, so to be perfectly clear:
I have X amount of memory available
I want Y number of enemies on screen
I want Z types of enemies to swap them out
I want infinite waves of enemies of various types for the player to shoot and be shot by
I don’t want to allocate memory at run-time (/Documentation/Manual/iphone-Optimizing-Scripts.html)
Does Instantiating() and enemy place him into memory regardless if activated or not?
Believe me I’ve been burning through the forums and the documentation to get a better idea on how to do this but I’m not clear how memory is handled with regards to prealloc.
Thanks again and sorry if I’m missing something being pounded into my head.
So am I being too frugal? I was concerned with storing ANY unnecessary verts into memory. My intial plan WAS to just have every ‘dynamic’ asset being under the game world and brought into play when needed.
Also, if I have 1 of each (weak/medium/strong) enemies, I AM only storing a reference for each additional instance correct? This is how ‘instancing’ works conventionally and I just want to be sure it’s the same here. Therefore I’m only storing the 3 datasets but then can have 20 instances of each off-screen ready to be recycled, and thus yes, no issue with mem.
Thanks for jumping in on this btw Pirate…I was tempted to come to you to ask you about this originally.