LODESTAR

Particles! Again, I know. A little more technical this time…

As you can see from the video, the particle origin is not completely in sync with the ‘real’ unit position. The effects are still snapping to the grid, but the framework is there! Don’t look at the bugs, look at the… Particles!

I used a simple system of assigning each particle an initial location and speed in x,y,z direction, gravity in x,y,z direction, and life. Some other variables are set in there too, like how much life is taken from the particle on each update (delta) and the master speed of the particle. I measure the life of a particle in milliseconds, and delta is milliseconds passed since last update. This is what my poison particle looks like:

public class ParticlePoison extends A_Particle {

  public ParticlePoison() {

    /*
     * Master speed
     */
    speed = 0.02f;
    rotSpeed = 0.01f;

    /*
     * Life
     */
    life -= rand.nextInt(1000);

    /*
     * Gravity
     */
    yg = 0.1f;
    
    /*
     * Initial speed
     */
    yi = 100;
    xi = rand.nextInt(2) - 1;
    zi = rand.nextInt(2) - 1;

    /*
     * Rotation speed
     */
    ys = rand.nextInt(30) - 15;

    /*
     * Size
     */
    float scale = 0.6f * rand.nextFloat() + 0.2f;

    /*
     * Initial position offset
     */
    float x = (rand.nextFloat() - 0.5f) * 5;
    float y = -3;
    float z = (rand.nextFloat() - 0.5f) * 5;

    /*
     * Make the entity
     */
    entity = new Entity(
      new SpatialCube(), 
      new TextureCube(
        Statics.TEXTURE_ATLAS_WHITE, 16, 16, 32, 32, 
          new int[] { 0, 0, 0, 0, 0, 0 }), 
      new Transform(x, y, z, scale));
    
    /*
     * Well, color me a particle...
     */
    entity.particle = true;
    entity.lightColor = new RGBA(
      0, 0.4f * rand.nextFloat() + 0.2f, 0, 1);
  }

  @Override
  public void _update(int delta) {
    
    float t = delta * 0.001f;
    float st = speed * t;
    
    /*
     * Update rotation
     */
    entity.transform.ry += ys * rotSpeed * t;

    /*
     * Update position
     */
    entity.transform.x += xi * st;
    entity.transform.y += yi * st;
    entity.transform.z += zi * st;

    /*
     * Update color
     */
    entity.lightColor.green -= 0.001f;

    /*
     * Update speed
     */
    xi += xg;
    yi += yg;
    zi += zg;

    /*
     * Update life
     */
    life -= delta;

    /*
     * Check life
     */
    if (life < 1) {
      active = false;
    }

  }

Emitters are attached to units on unit creation. Emitters can trigger themselves periodically or be triggered by external calls. Emitters ask the particle manager to add particles. The particle manager iterates through active particles, instructing to update and removing inactive particles. If too many particles are shown, the particle manager starts dropping requests from the emitters until there is room. I may add a priority to each particle that fades with time. Then older particles with less priority could be overwritten. However, that requires the particles to always be sorted by priority. Each type of particle can use its data to update itself in an independent fashion.

My mending particles store two colors, a start color and a finish color. Then, during the update, the mend particle slowly interpolates toward the finish color.

Also, I’m not restricted to using a cube as the entity, or visual representation, for the particle. A single quad can be used, or a pre-loaded VBO, such as a 3d sprite component.

On another topic, I spent too much time fiddling, trying to get some code to look nice on Tumblr. If you want to put code on Tumblr, I recommend this. However, wrap your code in <pre class=”prettyprint”></pre> only, skip the additional <code></code> nonsense.