Currently Yeti is working on a cross platform mobile game called Ripcord. The game’s main experience involves the player sky diving in different levels, where they need to avoid harmful objects in the sky, like birds and planes, while collecting coins. I’ve been building the Android version of the game and got the basic game play completed, but the game was looking flat.
I had not built any animations or effects that helped give the user the feeling of falling or feedback when they collide with an object so I went on a Google hunt for an android particle system tutorial/example/library that I could use. There were plenty of great websites involving particle systems for use with OpenGL, but none if you were just working with the regular android graphic library (which I am currently).
I figured at this point that I would just give it a try myself, while looking at one of the OpenGL examples for some guidance. The first effect I wanted to accomplish was for something in the background that would make it seem like the sky diver was falling. I also wanted to make whatever I built to be reusable so that it would not be hard to create the effect for the player colliding with another object.
The first class I created was ParticleSystem. This class took in a starting y position, a starting x position, an upper bound for the x position, a speed, an upper bound for the speed, number of particles, and the bitmap of the particle. This first effect would have every particle starting at the bottom of the screen and shooting upwards to create a wind like effect. The particles, when they reached the top of the screen would be removed and replaced with a new particle at the bottom of the screen at a random x position. They would also be given a random speed, within the speed range specified.
package com.yeti.ripcord;import android.graphics.Bitmap;import android.graphics.Canvas;public class ParticleSystem { private Particle particles[]; private int startYPos; private int startXPos; private int xPosRange; private int minSpeed; private int speedRange; private Bitmap bitmap; public ParticleSystem(int startYPos, int startXPos, int xPosRange, int minSpeed, int speedRange, Bitmap bitmap) { this.startYPos = startYPos; this.startXPos = startXPos; this.xPosRange = xPosRange; this.minSpeed = minSpeed; this.bitmap = bitmap; this.speedRange = speedRange; particles = new Particle[numParticles]; for (int i = 0; i < particles.length; i++) { particles[i] = new Particle(startYPos, startXPos, xPosRange, minSpeed, speedRange, bitmap); } } public void doDraw(Canvas canvas) { for(int i = 0; i < particles.length; i++) { Particle particle = particles[i]; particle.doDraw(canvas); } } 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] = new Particle(startYPos, startXPos, xPosRange, minSpeed, speedRange, bitmap); } } }}
Besides creating the initial particles in the constructor of the class, there would be two more functions updatePhysics and doDraw that will delegate to every particle in the system for their respective method calls. As you could guess, updatePhysics involves moving the particle’s position and deciding if it needs to be replaced, while doDraw draws the particle onto the canvas.
The Particle class was created next, where it also had the methods updatePhysics and doDraw as well as outOfSight. This method contains the logic for deciding if a particle is completely out of the canvas bounds. updatePhysics for this effect slowly decreases the y position of the particle while checking to see if it is out of sight. The variable passed into this method, distChange, is the amount of distance the player has fallen in the last game loop. This way, if the player starts to fall slower, the effect will also move slower, which looks pretty cool. doDraw draws the particle’s bitmap at its current x and y position.
package com.yeti.ripcord;import android.graphics.Bitmap;import android.graphics.Canvas;class Particle { private int xpos; private int ypos; private int speed; private Bitmap bitmap; public Particle(int startYPos, int startXPos, int xPosRange, int minSpeed, int speedRange, Bitmap bitmap) { xpos = startXPos + (int) (Math.random() * xPosRange); ypos = startYPos); this.speed = (int) (minSpeed + Math.random() * speedRange); this.bitmap = bitmap; } public void updatePhysics(int distChange) { ypos -= distChange * speed; } public void doDraw(Canvas canvas) { canvas.drawBitmap(bitmap, xpos, ypos, null); } public boolean outOfSight() { return ypos <= -1 * bitmap.getHeight(); }}
To use this particle system, you simply create a new one, with parameters appropriate for the effect you’re trying to make. Whenever your game loop calls methods that update the physics for your game or draws your game on the canvas, you need to call the respective methods on the particle system as well. From here it is very easy to change the update physics logic to do many different things depending on what kind of effects you’d like to create. In another post I will cover extending the ParticleSystem to create collision effects, where particles explode from the objects the sky diver hits.