yeti logo icon
Close Icon
contact us
Yeti postage stamp
We'll reply within 24 hours.
Thank you! Your message has been received!
A yeti hand giving a thumb's up
Oops! Something went wrong while submitting the form.

Android Particle System: Creating basic effects for games 2

By
Rudy Mutter
-
July 7, 2015

If you have not read our post Android Particle System: Create basic effects for games we recommend reading that first. If you have then keep reading!

After creating the background effect for our game it was time to work on the collision effect that would be triggered when the player’s sky diver hits an object while falling during a level. Sometimes these objects are helpful, like coins, while sometimes they are harmful, like birds.

Lets take the bird for example. When the skydiver hits the bird, an explosion of feathers should shoot out from the bird while the bird disappears. The individual feathers in the explosion should eventually start moving up and off of the screen, to give the feeling that the player is still falling after hitting the bird. This means we need to extend the ParticleSystem class made in the last post to take in some more inputs.

public ParticleSystem(int startYPos, int yPosRange, int startXPos, int xPosRange, int minSpeed, int speedRange, Bitmap bitmap, boolean respawnParticle, int numParticles, boolean isBursting) { this.startYPos = startYPos; this.yPosRange = yPosRange; this.startXPos = startXPos; this.xPosRange = xPosRange; this.minSpeed = minSpeed; this.bitmap = bitmap; this.speedRange = speedRange; this.respawnParticle = respawnParticle; this.isBursting = isBursting; particles = new Particle[numParticles];    for (int i = 0; i < particles.length; i++) {        particles[i] = new Particle(startYPos, yPosRange, startXPos,         xPosRange, minSpeed, speedRange,         bitmap, isBursting);    }}

yPosRange will allow us to randomize what height the feathers are created at in the explosion. respawnParticle will let us know if the particles need to be respawned after they are off of the screen. This will let us keep the existing functionality working for the background effect, while eliminating respawning for collision effects. isBursting indicates whether this effect should start with explosion physics. Also notice that we are passing in most of these new inputs to the Particle class as well.

Our updatePhysics function also has changed a bit. Now it needs to include the logic to check to see if it should be respawning particles or not after they have gone off the canvas. We also are setting a dead flag on the particle once it has gone out of sight so that it will not draw itself anymore or waste time calculating its movement.

public void updatePhysics(int altDelta) { for(int i = 0; i < particles.length; i++) { Particle particle = particles[i]; particle.updatePhysics(altDelta); // If this particle is completely out of sight // replace it with a new one. if(particle.outOfSight()) { particles[i].markDead(); if(respawnParticle) particles[i] = new Particle(startYPos, yPosRange, startXPos, xPosRange, minSpeed, speedRange, bitmap, isBursting); } } }

The bulk of the changes in this update to the particle system come in the Particle class. As you could of guessed, the constructor of the Particle class has now changed due to the newly added inputs. We now need to create a random starting y position within the range given as we had been doing for the starting x position. Also if this particle is bursting we need to choose a direction the particle will be exploding in. After figuring out where the particle is going to be randomly started at, we now know which quadrant it would be in if we considered the middle of the x and y range as the origin (0,0). We then pick a random angle between 0-90 degrees and that becomes the direction the particle is shooting in respect to the quadrant it is in. It is made to be a bit more complex so that particles created on two different sides of the particle system wouldn’t cross back over each other while shooting in opposite directions. Originally when this was happening, the effect did not look as good and did not give an explosion feeling.

public Particle(int startYPos, int yPosRange, int startXPos, int xPosRange, int minSpeed, int speedRange, Bitmap bitmap, boolean isBursting) { xpos = startXPos + (int) (Math.random() * xPosRange); ypos = startYPos + (int) (Math.random() * yPosRange); this.speed = (int) (minSpeed + Math.random() * speedRange); this.bitmap = bitmap; this.isBursting = isBursting; if(isBursting) { burstDistLimit = 30; angle = (Math.random() * (Math.PI / 2)); int midX = startXPos + (xPosRange / 2); int midY = startYPos + (yPosRange / 2); if(xpos < midX) negBurst = true; if(ypos < midY) angle *= -1; }}

A small change made to help optimize performance was to not draw the particle if it was marked dead.

public void doDraw(Canvas canvas) { if(!dead) canvas.drawBitmap(bitmap, xpos, ypos, null);}

The last change is found in the Particle’s updatePhysics method. First, if the particle is marked dead, then do not even bother calculating anything and just return out of the function. Secondly, if we’re in burst mode, then calculate the new position of the particle based on its trajectory we decided on in the constructor and how much distance the diver has traveled. Once the particle reaches its maximum burst distance (which is currently a static number, but could be changed) the particle will then fall out of burst mode and start to travel up and off of the screen.

public void updatePhysics(int distChange) { if(dead) return; if(isBursting) { int xPosChange = (int) (distChange * (double) (speed / 2.0)); if(negBurst) xPosChange *= -1; int yPosChange = (int) (xPosChange * Math.tan(angle)); totalXPosChange += xPosChange; totalYPosChange += yPosChange; if(Math.abs(totalXPosChange) > burstDistLimit || Math.abs(totalYPosChange) > burstDistLimit) { isBursting = false; } else { ypos += yPosChange; xpos += xPosChange; return; } } ypos -= distChange * speed;}

From here there are still many more modifications that could be made to the ParticleSystem for very different effects. Hopefully we will be posting more additions in the future.

Rudy Mutter is a CTO + Founding Partner at Yeti. He found his passion for technology as a youth, spending his childhood developing games and coding websites. Rudy now resides in the Yeti Cave where he architects Yeti’s system and heads up project production.

Follow Rudy on Twitter.

You Might also like...

colorful swirlsAn Introduction to Neural Networks

Join James McNamara in this insightful talk as he navigates the intricate world of neural networks, deep learning, and artificial intelligence. From the evolution of architectures like CNNs and RNNs to groundbreaking techniques like word embeddings and transformers, discover the transformative impact of AI in image recognition, natural language processing, and even coding assistance.

A keyboardThe Symbolicon: My Journey to an Ineffective 10-key Keyboard

Join developer Jonny in exploring the Symbolicon, a unique 10-key custom keyboard inspired by the Braille alphabet. Delve into the conceptualization, ideas, and the hands-on process of building this unique keyboard!

Cross-Domain Product Analytics with PostHog

Insightful product analytics can provide a treasure trove of valuable user information. Unfortunately, there are also a large number of roadblocks to obtaining accurate user data. In this article we explore PostHog and how it can help you improve your cross-domain user analytics.

Browse all Blog Articles

Ready for your new product adventure?

Let's Get Started