Particle System Tutorial on Android


Particle systems are a way to add effects to a game, like an explosion, fire, or water fountain. They usually don’t interact with each other or the world around them, to improve performance. Even a simple system can have 50 particles which are a lot of polygons to do for an effect. First, you’ll want to start a new Android project and paste in the simplest GLSurfaceView application from the Google Android Blog. This is a great starting point for any OpenGL app on Android, I use it all the time when starting a new OpenGL project. It really helped me get up and running quickly so I could start learning more about OpenGL rather than struggle with learning Android and OpenGL at the same time.

First, we need to make a particle object.

package com.bayninestudios.particlesystemdemo;

import java.util.Random;

public class Particle {

    // location
    public float x;
    public float y;
    public float z;

    public Particle(Random gen)
    {
        this.x = gen.nextFloat();
        this.y = gen.nextFloat();
        this.z = gen.nextFloat();
    }
}

Simple particle with an x,y,z coordinate and assigned a random value between 0 and 1. The local variables are public, rather than using getters and setters for performance reasons. Now this particle needs to belong in a system.

package com.bayninestudios.particlesystemdemo;

import com.bayninestudios.particlesystemdemo.Particle;

public class ParticleSystem {
    private Particle[] mParticles;
    private int PARTICLECOUNT = 20;
	
    public ParticleSystem() {
        mParticles = new Particle[PARTICLECOUNT];

        Random gen = new Random(System.currentTimeMillis());
        for (int i=0; i < PARTICLECOUNT; i++) {
            mParticles[i] = new Particle(gen);
        }
    }
}

Simple. Now we have to draw everything. Rather than have a draw routine for each particle, with an assigned texture and vertexes, I have one object that gets allocated by the system and drawn. For each draw, you'll need to do the appropriate translates for the position of the particle. The ParticleSystem class will need a vertex buffer and index buffer to define the triangle to draw. I've also added two helper methods to convert float or short arrays to native order buffers. In previous Android versions I just used FloatBuffer.wrap(float[]) but newer versions require the native order buffers.

    // for use to draw the particle
    private FloatBuffer mVertexBuffer;
    private ShortBuffer mIndexBuffer;
	
    public ParticleSystem() {
        mParticles = new Particle[PARTICLECOUNT];

        Random gen = new Random(System.currentTimeMillis());
        for (int i=0; i < PARTICLECOUNT; i++) {
            mParticles[i] = new Particle(gen);
        }

        float[] coords = {
                -0.1f,0.0f,0.0f,
                0.1f,0.0f,0.0f,
                0.0f,0.0f,0.1f};
        short[] icoords = {0,1,2};

        mVertexBuffer = makeFloatBuffer(coords);
        mIndexBuffer = makeShortBuffer(icoords);
    }

    // use to make native order buffers
    private FloatBuffer makeFloatBuffer(float[] arr) {
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer fb = bb.asFloatBuffer();
        fb.put(arr);
        fb.position(0);
        return fb;
    }

    // use to make native order buffers
    private ShortBuffer makeShortBuffer(short[] arr) {
        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
        bb.order(ByteOrder.nativeOrder());
        ShortBuffer ib = bb.asShortBuffer();
        ib.put(arr);
        ib.position(0);
        return ib;
    }

Also ParticleSystem will need a draw routine. This routine setups the vertex buffer to use, the color, translates the draw to the location of the particle, and draws it.

    public void draw(GL10 gl) {
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
        gl.glColor4f(1f, 1f, 1f, 1f);
        for (int i = 0; i < PARTICLECOUNT; i++) {
            gl.glPushMatrix();
            gl.glTranslatef(mParticles[i].x, mParticles[i].y, mParticles[i].z);
            gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
            gl.glPopMatrix();
        }
    }

Finally, in the main ParticleSystemDemo class, create a new ParticleSystem, initialize the GL perspective and call the draw routine.

class ClearRenderer implements GLSurfaceView.Renderer {
    private ParticleSystem mParticleSystem;
	
    public ClearRenderer() {
        mParticleSystem = new ParticleSystem();
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLU.gluPerspective(gl, 15.0f, 80.0f/48.0f, 1, 100);
        GLU.gluLookAt(gl, 0f, -10f, 15f, 0.5f, 0.0f, 0f, 0.0f, 1.0f, 1.0f);
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) {
        gl.glViewport(0, 0, w, h);
    }

    public void onDrawFrame(GL10 gl) {
    	gl.glClearColor(0, 0, .5f, 1.0f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        mParticleSystem.draw(gl);
    }
}

After all of this you should have a blue background with a bunch of triangle particles in the middle of the screen. They don't move yet but that will be for part two of this. There are other improvements to make, possibly having the system assign the initial location of the particle. Randomizing the color. The particle size is hardcoded, and could be dynamic if needed. Texture mapping the particles. Moving the particle drawing to a different class, that way there can be multiple particle models for the same system.

The most recent code can be found at Bay Nine Studios on Google Code.

8 thoughts on “Particle System Tutorial on Android

  1. Did you download the zip file for the code or cut and paste it from the blog entry? If you send me your code I could have a quick look, email bayninestudios@gmail.com. Also, I’m working on getting the third tutorial and all the tutorials on the market for download. Going to combine all of them into one app that you can then choose which demo to see.

  2. Vienna, thanks for helping me figuring out to add glEnableClientState(GL10.GL_VERTEX_ARRAY);
    Updating the entry to reflect the change

  3. The project starts too fast for me. I don’t have enough specifics- i.e. step one: this code in this file. Or here is what the package explorer looks like now.

    I will try again after going to other tutorials. A zipped project would help me. Can’t wait to start because it looks to be a good tutorial if I could just get it going. Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>