Utilizing Particle Effects to Enhance Your Cocos2D App
Particle systems allow for the simulation of explosions, fire, snow, and other special effects. The Cocos2D-iPhone framework provides the ability to easily implement these various effects and then some. With little effort, the developer can easily increase the wow factor of their applications. A review of the Cocos framework’s sample files shows code examples to do 16 different particle effects. Some of these examples are shown in the following screen captures.
After seeing some recent online discussions regarding the use of particles, I thought it would be worthwhile to pass along some information that I had found useful when implementing a simple particle effect for one of my applications, Crazy Cupid.
I had been wanting to try out particle effects because I’d noticed more and more applications using them, and I felt most of the time they added a nice visual impact. In Crazy Cupid, the cupid’s flight direction is controlled through accelerometer input. User’s touches anywhere on the screen causes the cupid to fire an arrow with the intention of hopefully hitting one of the Valentine goodies.
The collision of the cupid’s arrow with an object triggers several events such as removing the arrow and impacted object from the screen, updating the score, initiating a sound effect, and ultimately calling a particle effect. The displayed effect after an impact is captured in the following screen capture, which shows several multi-colored star bursts.

For this application, it was my first go around using both Chipmunk physics and particles. And I quickly learned the importance of optimization as I was incredibly disappointed to see frame rates in the teens. Even though the application has the provision of only handling 12 arrows at a time, the user can basically bang away on the screen pretty much as fast as they can and essentially create an endless stream of arrows. While I’ll cover optimization in another upcoming article, I wanted to stress for this discussion just the use of particles and the need to clean house upon completion of a particle effect.
Initially, my game would start out with acceptable frame rates. But after a minute’s worth of user touches, which triggered hundreds of particle effects, the frame rate would steadily drop. Clearly something was being retained and consuming resources.
After looking through the ParticleSystem class in more detail I eventually found the following boolean parameter:
emitter.autoRemoveOnFinish = YES;
Maybe this is common sense and known by the seasoned programmers, but for me it was just what I needed to fix the degrading frame rate. Specifically, with this value set to YES, the following is performed within the Cocos2D PointParticleSystem.m class.
if( particleCount == 0 && autoRemoveOnFinish_ ) {
[self unschedule:@selector(step:)];
[[self parent] removeChild:self cleanup:YES];
}
I later found this switch also within the Cocos2D demo particle class but not for every example, so it’s easily overlooked. With the autoRemoveOnFinish set, my game was back on track and not experiencing any degradation no matter how long you played.
The following is the particle code used within the app. The parameters are labeled and pretty much self explanatory. Given the rapid frequency I was calling this effect, I experimented with the settings so as to still give a nice effect but at reduced stress to the system. For instance, I found that the visual difference between say 30 and 60 particles wasn’t that significant, but the performance savings was more pronounced.
-(void) createExplosionX: (float) x y: (float) y
{
[emitter resetSystem];
// ParticleSystem *emitter = [RockExplosion node];
self.emitter = [[QuadParticleSystem alloc] initWithTotalParticles:30];
emitter.texture = [[TextureMgr sharedTextureMgr] addImage: @"stars.png"];
// duration
// emitter.duration = -1; //continuous effect
emitter.duration = 1;
// gravity
emitter.gravity = CGPointZero;
// angle
emitter.angle = 90;
emitter.angleVar = 360;
// speed of particles
emitter.speed = 160;
emitter.speedVar = 20;
// radial
emitter.radialAccel = -120;
emitter.radialAccelVar = 0;
// tagential
emitter.tangentialAccel = 30;
emitter.tangentialAccelVar = 0;
// life of particles
emitter.life = 1;
emitter.lifeVar = 1;
// spin of particles
emitter.startSpin = 0;
emitter.startSpinVar = 0;
emitter.endSpin = 0;
emitter.endSpinVar = 0;
// color of particles
ccColor4F startColor = {0.5f, 0.5f, 0.5f, 1.0f};
emitter.startColor = startColor;
ccColor4F startColorVar = {0.5f, 0.5f, 0.5f, 1.0f};
emitter.startColorVar = startColorVar;
ccColor4F endColor = {0.1f, 0.1f, 0.1f, 0.2f};
emitter.endColor = endColor;
ccColor4F endColorVar = {0.1f, 0.1f, 0.1f, 0.2f};
emitter.endColorVar = endColorVar;
// size, in pixels
emitter.startSize = 20.0f;
emitter.startSizeVar = 10.0f;
emitter.endSize = kParticleStartSizeEqualToEndSize;
// emits per second
emitter.emissionRate = emitter.totalParticles/emitter.life;
// additive
emitter.blendAdditive = YES;
emitter.position = cpv(x,y); // setting emitter position
[self addChild: emitter z:10]; // adding the emitter
emitter.autoRemoveOnFinish = YES; // this removes/deallocs the emitter after its animation
My end of level effects were slightly modified to create larger particles as shown in the following screen capture. Overall I think the effects were visually appealing and added some additional polish to a relatively straight forward game.
I hope this brief particle discussion has been useful and will save you time when implementing some easy but spectacular effects. Feel free to comment with suggestions and recommendations.



Hey, nice post! I’ve been playing around with particle effects too for my game and hadn’t noticed the autoRemoveOnFinish
parameter, thanks for pointing that out!
Looking forward to your post on optimization as well!
Hi,
Would you explain more details about angle, radialAccel and tangentialAccel? When setting 90 to angle, what does that mean? 90 degree to what?
I would appreciate if you could email as well.
Thanks.
Pak,
I hadn’t really given much thought to those particular values, but I’d experimented with the quantity, speed, and particle size previously.
Take a look at the following for a bit more detail on the class: Particle.m
In looking over the values and respective formulas within the Particle.m class, it looks like the angle is relative to the emitter location and in a quick test with the angle at 90deg with no variance, the particles not surprisingly emit straight up, while at -90 they were straight down.
And in looking at the initParticle method within the class we see where these values are put to use to affect the direction of the emitted particles:
// direction
float a = (cpFloat)CC_DEGREES_TO_RADIANS( angle + angleVar * CCRANDOM_MINUS1_1() );
v.y = sinf( a );
v.x = cosf( a );
float s = speed + speedVar * CCRANDOM_MINUS1_1();
particle->dir = cpvmult( v, s );
Hope that provides a bit more insight.
I was reading through the code you posted and I am not sure how to use the emitter.autoRemoveOnFinish = YES;.
My frame rate goes down real fast to 12 from 60.
Any suggestions?
here’s how I instantiate the emitter…in the init method…
//emitter = [[CCParticleMeteor alloc] init];
emitter = [[CCParticleFire alloc] init];
emitter.texture = [[CCTextureCache sharedTextureCache] addImage:@”particle.png”];
emitter.position = ccp(340,160);
[self addChild:emitter];
emitter.autoRemoveOnFinish = YES;
I’d appreciate some help.
Thanks
Tony,
I think one issue is that the autoRemoveOnFinish will be applicable to those emissions that have a duration, and when using the fire it’s continuous. I haven’t played with the fire particle but I reviewed the sample code in the framework and had the following working without killing my frame rate:
emitter = [CCParticleFire node];
emitter.texture = [[CCTextureCache sharedTextureCache] addImage: @”fire.pvr”];
emitter.position = cpv(x,y); //this placed the fire where ever I had an impact based on the coordinates I fed it
[self addChild: emitter z:10];
Then when I wanted to remove the fire I used the following:
[self removeChild:emitter cleanup:YES];
Hope that helps.
I really liked your blog! great