This is not considered as a whole tutorial, this is some kind of fixing some stupid stuff we did back in the the previous one and caused android to struggle [sorry android >_<] and reduced performance
If you ever checked the logcat while the application is running, you may have noticed that the Garbage collector was running a lot , that’s because we were creating objects and just leaving them floating around, when the android system needs extra ram [or when it just decides that it wants to run the garbage collector just for the heck of it] it’d remove those objects we created and we create some more .. so here we are presenting the solution for this:
Introducing Awesome Recycling Thingie !!!! [or just pools]
The idea of pools is to create an object on need, when you are done with it you give it back to the pool for reuse
I found a great tutorial on using Generic pools from c0deattack where he describes using bullets pools as:
Game: I need a bullet! Mr. Object Pool can I have an instance of a Bullet please?
Mr. Object Pool: Let me check my pool…I don’t have spare Bullets, I’ll create a new Bullet for you
Game: Thanks!
Game: Mr. Object Pool, this bullet has moved offscreen so I don’t need it anymore, please recycle it for me
Mr. Object Pool: Ok, thanks, I’ll put that instance in my pool
Game: Hey, I need another Bullet again
Mr. Object Pool: No problem, I have one in my pool which you gave me, I don’t need to waste time making a new Bullet, you can have this one!
perfect , right ?
it’s actually quite easy to use too ..
Creating the pool
Create a new class that extends GenericPool, I named it ProjectilesPool, here’s the whole class
public class ProjectilesPool extends GenericPool<Sprite> { private TextureRegion mTextureRegion; public ProjectilesPool(TextureRegion pTextureRegion) { if (pTextureRegion == null) { // Need to be able to create a Sprite so the Pool needs to have a TextureRegion throw new IllegalArgumentException("The texture region must not be NULL"); } mTextureRegion = pTextureRegion; } /** Called when a projectile is required but there isn't one in the pool */ @Override protected Sprite onAllocatePoolItem() { return new Sprite(AndEngineSimpleGame.player.getX(),AndEngineSimpleGame.player.getY(), mTextureRegion.deepCopy()); } /** Called when a projectile is sent to the pool */ protected void onHandleRecycleItem(final Sprite projectile) { projectile.clearEntityModifiers(); projectile.clearUpdateHandlers(); projectile.setVisible(false); projectile.detachSelf(); projectile.reset(); } }
here’s an explanation for what’s going on, the class constructor takes texture region for the object you want [in our case it’ll be our mProjectileTextureRegion].
onAllocatePoolItem() is called when we need to create a new projectile sprite, so we use our mTextureRegion and set the position as the player’s position [don’t forget to change the modifier of the player’s sprite to static]
onHandleRecycleItem() is called when you want to recycle an item [return a projectile to the pool], just clear everything and let it detach itself from the main scene .. pretty straight forward
now , let’s use that shall we ?
Using the pool
in our BaseGameActivity [AndEngineSimpleGame.java] declare this
ProjectilesPool pPool;
[don’t read the fast or you’ll get the image of a yellow pool]
initialize it in onLoadResources()
pPool = new ProjectilesPool(mProjectileTextureRegion);
let’s go to our shootProjectile() method and make a use of our new pool
Sprite projectile; // position the projectile on the player projectile = pPool.obtainPoolItem();
This will get us a recycled projectile to use [save the planet !]
let’s modify our detect IUpdateHandler to make a use of the pool too, whenever you see a removeSprite() method call for the projectiles, replace it with
pPool.recyclePoolItem(_projectile); projectiles.remove();
and you are all set, launch and enjoy your environment friendly game
Now what ?
now you go ahead and create another pool for the targets to use, it’s basically the same thing so you should be able to do it yourself, you’ll notice that you won’t be using the removeSprite() method anymore , so just remove it
but if you had problems with it, you can download the whole project’s source code
for any questions , drop a comment [comments gives me that nice feeling inside :P]
You can also continue with the next part of the tutorial’s series here
explanations very well done thank you
Thank you very very VERY much! Great tutorials.
Great tutorials..Thank you :-bd
didn’t work form me , i get “IllegalStateException: pEntity already has a parent! “
Are you sure you did the code the same way it’s written ?
you should make sure that you detach the projectile when you are done with it “projectile.detachSelf();” inside “onHandleRecycleItem”
if you are not sure what’s wrong then post your codes [both files] on http://pastebin.com/ and share the link
it’s ok now, i restarted eclipse, cleaned project and it worked, i guess eclipse needed to rest…
Thank you very much, Jimmar. You are the man !
thanks for the great tutorial…!..yours are the best tutorials i have come across so far…!
but i am facing a problem….i followed your first tutorial..and it worked quiet well..but the pool tutorial you provided didn’t work..!…the strange thing is it shows red cross on the project saying it has an error but i cant really find any error in the code any where..neither is there any red cross in the code section…i guess it has something to do with the properties..but i have almost tried every thing in the properties section but cant make it work…!!!..please help…!!
thanks in advance..
urgh , I used to get this error sometimes too >.clean projects] and restarting eclipse , if that didn’t work then it could be that your keystore expired.
to fix that , go to the .android folder [if using windows it’s in the user folder, for me it’s C:\Users\JiMMaR\.android , if using linux it’s /home/.android/ I think] and delete the debug.keystore file , running the game again from eclipse should have it regenerated for you.
this is not your fault [and not mine too :P]
ohh…ok…I actually followed the tutorial and developed the game again instead of copying ready-made project you provided(which i was trying earlier and was getting that error..:P) and its working now….thanks man…you really have done an excellent job…every other example tutorial i have searched on the internet is either incomplete or with no explanation at all..and its a nightmare out there for a beginner….your tutorials really are a life saver… hats off…!!!!(and sorry for the terrible english..:P…not my native language)..
I’m glad you liked it , and yeah I had the same problem when I started with andEngine and this was my first project [took me some time to figure out how stuff work] so I thought about making it into a real tutorial.
am glad that I wrote it in a simple enough way for people to understand 😀
[don’t apologize , your English is good and it’s not my native language too anyway :P]
Hi, i have the same problem as ivica, i created the pool but it throws the exception: pEntity already has a parent!, i cleaned the project but it continues throwing the expcetion
my code:
//Handler para recorrer todas las coins y comprobar si han llegado al suelo
IUpdateHandler detect = new IUpdateHandler() {
public void onUpdate(float pSecondsElapsed) {
Iterator coins = coinLL.iterator();
Sprite _coin;
int puntos = 0;
boolean hit = false;
while (coins.hasNext()) {
_coin = coins.next();
//Si pasa del suelo la añadimos al pool
if (_coin.getY() >= mCamera.getHeight()) {
pCoins.recyclePoolItem(_coin);
coins.remove();
break;
}
if (_coin.collidesWith(player)) {
removeSprite(_coin, coins);
hit = true;
}
}
coinLL.addAll(CoinsToBeAdded);
CoinsToBeAdded.clear();
}
public void reset() {
}
};
— The code in CoinsPool.java
public void onHandledRecycleItem (final Sprite coin) {
coin.detachSelf();
coin.clearEntityModifiers();
coin.clearUpdateHandlers();
coin.setVisible(false);
coin.reset();
}
hi again!, i have found the solution but, i think is not “legal”:
code:
IUpdateHandler detect = new IUpdateHandler() {
public void onUpdate(float pSecondsElapsed) {
Iterator coins = coinLL.iterator();
Sprite _coin;
int puntos = 0;
boolean hit = false;
while (coins.hasNext()) {
_coin = coins.next();
//Si pasa del suelo la añadimos al pool
if (_coin.getY() >= mCamera.getHeight()) {
pCoins.recyclePoolItem(_coin);
_coin.detachSelf();
_coin.clearEntityModifiers();
_coin.clearUpdateHandlers();
_coin.setVisible(false);
_coin.reset();
coins.remove();
//removeSprite(_coin, coins);
//break;
}
if (_coin.collidesWith(player)) {
removeSprite(_coin, coins);
hit = true;
}
}
coinLL.addAll(CoinsToBeAdded);
CoinsToBeAdded.clear();
}
public void reset() {
}
};
Yeah , I faced this problem before too .. it happens because I didn’t use the synchronize block [I’m using that in my Jimvaders tutorial check it out]
I think just making it detachSelf() before attaching is enough [not after recycling]
I think I should redo those series of tutorials now … too much work though >_<
No problem! You did a very good job with this tutorials, are very useful Thnx!!
Mr. Jimmar:
Great Toutorial! I had been trying with and engine for like 6 months and couldn’t get it to work untill now..
I just have one question..
How would you make the “bad guys” start comming faster and fastaer each time you kill one?.
Thanks a lot in advance.
glad that I was able to help XD
And for your question , you can have the delay variable in createSpriteSpawnTimeHandler() be a public variable, and whenever you hit something you reduce the delay “mEffectSpawnDelay” by some amount
you’ll also have to modify the timehandler object so it uses the new time for every cycle
[remember to reduce the coolDown for the bullets too .. the player won’t be able to hit anything with a coolDown as high as I had
Yeah but the spriteSpawnTimeHandler() is only called like 6 times since all the others are used by the pool (if I’m not wrong) I’m new at this.
No , the spawn handler gets called every mEffectSpawnDelay second.
it gets called regardless of what the pool contains .. the pool only manages if it needs to create a new object or reuse an old one
onHandleRecycleItem() should be Overrided, isnt it?
The @Override annotation is not necessary, it gets overridden anyway
OMG what the heck are you doing here?
projectile.clearEntityModifiers();
projectile.clearUpdateHandlers();
projectile.setVisible(false);
projectile.detachSelf();
projectile.reset();
All you need is setVisible(false) and setIgnoreUpdate(true);
Why detach ? why reset ?
I wrote this blog post as a general post about pools that’s being applied to the previous tutorial
so I thought I’d clean everything up and reset .. you don’t have to do that if you don’t want to 😀
Jimmar thanks a lots for ur works.
i follow ur tutorial. Now i want to delete the individual spirit when they are touched. Where i implement IOtouchListener? Inside addTaget() or update() in IUpdateHandler?
can u help mein this issue.?
you can do it the same way I’m using to move the hero, just apply that to all the enemies or you can just check the touch and see if it collides with other objects or not
Ya. i got it. I query was to remove sprite when it touched. and successfully i finish it. i have a question
1) instead of using pool, i use as usual animated sprite object calling. Is there any optional way to handle object which are passed on the screen?
i post my problem here. and then give a solution also. can check & reply me.
http://stackoverflow.com/questions/13007822/remove-sprite-when-touched
Thanks for your kind reply.
keep in touch brother.
man, the link for the source code is off…
can you upload it again?
thanks
Done [let’s hope that dropbox doesn’t get mad about this :P]
Very nice! Do you have more tutorials about optimizations? Thanks!!