- Home /
How do you use a pool of objects rather than creating and destroying repeatedly?
How can I create and pull from a pool of reusable objects (like bullets, enemies, explosions, etc) rather than Instantiating and destroying them during gameplay?
I've seen several forum responses mention that you should create a pool of objects at Start and pull from them when needed however, I've never seen any complete script and/or scene setup examples of how to do it.
Answer by Brian-Kehrer · Nov 18, 2009 at 05:51 AM
It depends on how much you know about your game. The more you know the more optimizations you can make.
Lets assume you need bullets, and in your game you know there will never be more than 1000 bullets on screen at once.
This is the start of a class which will get you the next bullet in the array when asked.
public class BulletGetter : MonoBehaviour {
GameObject[] bullets;
int lastBullet = -1;
int bulletCache = 1000;
void Awake(){
bullets = new GameObject[bulletCache];
for(int i=0; i<bullets.Length; i++){
bullets[i] = new GameObject ("Bullet-"+i);
}
}
int GetNextBullet(){
lastBullet +=1;
if(lastBullet > bulletCache-1){
lastBullet = 0;//reset the loop
}
return lastBullet;
}
}
Various improvements could be made to this, such as activating and deactivating bullets as they are in use, automatically increasing the array size if you for some reason end up with more than 1000 bullets on screen, etc. Also, instead of creating gameObjects, you could instantiate prefabs in awake.
The most important part of doing a caching system is making sure all your cached objects have a method which will return them to their original unused state. Since you no longer will simply destroy and create a new object, its helpful to code your scripts in such a way that you can easily track and revert the state of the object.
Thanks, this is very helpfu Brain.
Would anyone like to add a Javascript example as well?
In Javascript:
var bullets : GameObject[]; var lastBullet : int = -1; var bulletCache : int = 1000;
function Awake(){ bullets = new GameObject[bulletCache]; for(var i : int=0; i
}
function GetNextBullet(){ lastBullet +=1; if(lastBullet > bulletCache-1){ lastBullet = 0;//reset the loop } return lastBullet; }
Thanks a lot for this, it has helped me to understand arrays a lot better.
I finally got around to digging into this example, and it's creating the pool of bullets when the level starts (nice!). But I'm not sure how to get the bullet (eg. bullet-0) GameObjects and reference them in my script for shooting them, returning them to their original state after impact, etc.
If you make the functions public and attach a reference to the bullet$$anonymous$$anager (or create a singleton bullet$$anonymous$$anager), you can call the get functions, and then reference the array like
GameObject myBullet = theBullet$$anonymous$$anager.bullets[theBullet$$anonymous$$anager.GetNextBullet()];
Answer by rocket5tim · Dec 20, 2009 at 04:48 PM
I had a different answer here before which was pretty convoluted and probably not very helpful. Here's a revised script which is similar to Brain's but more complete.
Here's the main code for handling the object pool (bullets in this case):
public class BulletPool : MonoBehaviour {
public Bullet[] bullet;
private int bulletCache = 0;
private int activeBullet = 0;
void Start () {
bulletCache = (bullet.Length);
}
void FireBullet() {
bullet[activeBullet].Fire(); // fire the bullet
activeBullet+=1;
if(activeBullet > bulletCache-1){
activeBullet = 0;//reset the loop
}
}
}
This script is called every time a bullet is fired, add code to this script to handle bullet movement and other behaviors:
public class Bullet : MonoBehaviour {
void Fire() {
// code that makes your bullet move
}
}
Sorry I never got back to this:
Your code looks fine. You may want to move the Recycle function onto the bullet, (so it can use it's cashed transform, etc) and then just have the manager call Bullet.Recycle(). Same idea for the creation. $$anonymous$$ostly it just makes the code cleaner, but also using the cached transforms is beneficial.
What does
bulletArray[index] = newBullet.GetComponent(Bullet);
do?
Answer by Ehren · Jan 06, 2010 at 09:34 PM
Here's a javascript pool class I developed for Intergalactic Sheep Pong. It allows you to pre-instantiate a specific number of prefab instances. It will also dynamically grow if you end up needed more objects than you originally allocated.
A simple array is more efficient if you know the maximum number of objects you need to instantiate, but the .NET collections are pretty fast, too, and support dynamic resizing.
I hope this is helpful. If anyone has any suggestions on how this code could be improved, feel free to comment.
Answer by Spk · Sep 01, 2010 at 09:24 AM
Here's the ObjectPoolManager I wrote for several of my games: http://forum.unity3d.com/viewtopic.php?t=36691&highlight=objectpoolmanager
I'm using it on iPhone as well but this package is an older version that uses some generics that aren't supported yet on Unity iPhone 2.6 - It should work as is in the upcoming Unity 3 though.
Answer by webphone · Jun 29, 2010 at 12:20 PM
Hi meanstreak
I tried to use your code to preload bullets.
There is a shootJoystick button in my game, I want the preloaded bullets to be fired when I pressed that button.
if(shootJoystick.IsFingerDown()) { for (var i = 0; i < iPhoneInput.touchCount; ++i) { var touchObj : iPhoneTouch = iPhoneInput.GetTouch(i); if (touchObj.phase == iPhoneTouchPhase.Began) { var bullet : GameObject = Instantiate(bulletPrefabs, spawnPoint.transform.position, spawnPoint.transform.rotation) as GameObject;
bullet.rigidbody.AddForce(transform.forward * 2000, ForceMode.Acceleration);
}
}
}
How should I load the preloaded bullet from BulletPool.js?
Replace this code: var bullet : GameObject = Instantiate(bulletPrefabs, spawnPoint.transform.position, spawnPoint.transform.rotation) as GameObject;
//where spawnPoint is the start bullet firing point from character.
And, how to add movement in Bullet.js:
function Update () {
// your own bullet movement code bulletPool.rigidbody.AddForce(transform.forward * 2000, ForceMode.Acceleration); // is it? }
Thanks for advice
hi webphone, this should have been a new question ins$$anonymous$$d of an answer as Ricardo mentioned. Anyway, your question is kinda old now so hopefully you figured it out by now. Let me know if you still need help.