Like in topic. I made my own particle generator for 2D games in LWJGL. It seems to be very efficient, 50000 particles use about 80% of my CPU power. You can set many parameters and use your own particle texture. Textures for this generator should have alpha background and white color.
I am using this code to make engine particles in my space game, I think that effects are looking good.
Particle_Generator class:
package Game;
import de.matthiasmann.twl.utils.PNGDecoder;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL11.*;
public class Particle_Generator {
int particleCount = 0;
int generationSpeed = 0;
int generationNow = 0;
Particle[] particles;
private float x = 0;
private float y = 0;
private int life = 0;
private float r = 0;
private float g = 0;
private float b = 0;
private float a = 0;
private boolean emitter = false;
private float speed = 0;
private float angle = 0;
private float range = 0;
ByteBuffer bufParticle;
PNGDecoder decParticle;
private class Particle {
private Particle_Generator daddy = null;
private float x = 0.0f;
private float y = 0.0f;
private float speed = 1.001f;
private float r = 0;
private float g = 0;
private float b = 0;
private float a = 1;
private float personalAngle = 0;
private float lifespan;
private float angleDiff = 0;
private boolean dead = false;
public Particle(Particle_Generator generator) {
daddy = generator;
r = (float) (daddy.r + (Math.random()/10));
g = (float) (daddy.g + (Math.random()/10));
b = (float) (daddy.b + (Math.random()/10));
a = (float) (daddy.a + (Math.random()/10));
x = daddy.x;
y = daddy.y;
lifespan = daddy.life;
speed = (float) (daddy.speed + (Math.random()*daddy.speed/10));
personalAngle = daddy.angle;
float rangecalc = (float) Math.random();
boolean isAboveZero = false;
if(rangecalc>.5) {isAboveZero = true;}
rangecalc = (float) Math.random();
if (isAboveZero==true) {angleDiff = daddy.range*rangecalc;}
else {angleDiff = -range*rangecalc;}
personalAngle = personalAngle + angleDiff;
}
private void update() {
if(Math.random()>.5){
x += 1*Math.random();
}
else{
x -= 1*Math.random();
}
if(Math.random()>.5){
y += 1*Math.random();
}
else{
y -= 1*Math.random();
}
x -= Math.sin(personalAngle) * speed;
y += Math.cos(personalAngle) * speed;
draw();
weaken();
}
private void draw() {
glColor4d(r,g,b,a);
glTexCoord2d(1,0); glVertex2d(-10, -10);
glTexCoord2d(1,1); glVertex2d(-10, 10);
glTexCoord2d(0,1); glVertex2d(10, 10);
glTexCoord2d(0,0); glVertex2d(10, -10);
}
private void move(float x, float y){
this.x=x;
this.y=y;
}
private void weaken(){
lifespan--;
if (lifespan<0) {dead=true;}
}
}
public Particle_Generator(int size, int generate, int life, float r, float g, float b, float a, boolean emit, float x, float y, float speed, float angle, int range) {
if(size<=0) {
return;
}
particleCount = size;
generationSpeed = generate;
this.r = r;
this.g = g;
this.b = b;
this.a = a;
this.x = x;
this.y = y;
this.life = life;
this.speed = speed;
this.angle = angle;
this.range = (float) (range*Math.PI/180);
emitter = emit;
generate();
particleTexture();
}
private void generate() {
particles = new Particle[particleCount];
for(int i = 0; i < particleCount; i++) {particles[i] = new Particle(this);}
for(int i = 0; i < particleCount; i++) {particles[i].lifespan = 1;}
}
public void update(boolean produce) {
for(int i = 0; i < particleCount; i++) {
if(particles[i] != null){
if(particles[i].dead==true){
particles[i] = null;
}
else {particles[i].update();}
}
else{
if (produce==true) {
particles[i] = null;
if(emitter){
if (generationSpeed>generationNow) {
particles[i] = new Particle(this);
generationNow++;
}
}
}
}
}
generationNow = 0;
}
public void draw() {
for(int i = 0; i < particleCount; i++) {
if(particles[i] != null){
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decParticle.getWidth(), decParticle.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, bufParticle);
glBindTexture(GL_ADD, GL_LOAD);
glBindTexture(GL_TEXTURE_2D,1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glPushMatrix();
glTranslated(particles[i].x+Core.SCREEN_X/2, particles[i].y+Core.SCREEN_Y/2, 0);
glBegin(GL_QUADS);
particles[i].draw();
glEnd();
glPopMatrix();
}
}
}
public void move(float x, float y){
this.x = x;
this.y = y;
}
public void killme(){
for(int i = 0; i < particleCount; i++) {
if (particles[i]!=null) {
particles[i] = null;
}
}
}
public void setspeed(float Speed){
this.speed = Speed;
}
public void setAngle(float Angle){
this.angle=Angle;
}
public void setRange(float Range){
this.range=(float) (Range*Math.PI/180);
}
public void particleTexture() {
InputStream in = null;
try {
in = new FileInputStream(YOUR_PARTICLE_TEXTURE);
} catch (FileNotFoundException ex) {
Logger.getLogger(Models.class.getName()).log(Level.SEVERE, null, ex);
}
try {
decParticle = new PNGDecoder(in);
bufParticle = ByteBuffer.allocateDirect(4*decParticle.getWidth()*decParticle.getHeight());
decParticle.decode(bufParticle, decParticle.getWidth()*4, PNGDecoder.Format.RGBA);
bufParticle.flip();
} catch (IOException ex) {
Logger.getLogger(Models.class.getName()).log(Level.SEVERE, null, ex);
}
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(Models.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Use this code to create new generator:
Particle_Generator generator;
generator = new Particle_Generator(MAX_NUMBER_OF_PARTICLES, PARTICLES_PER_UPDATE, LIFE_LENGTH, COLOR_R, COLOR_G, COLOR_B, ALPHA, START_AT_CREATION, POSITION_X, POSITION_Y, PARTICLES_SPEED, ANGLE, RANGE);
Update particles logic and life time:
generator.update(true); //update existing particles and generate new ones
generator.update(false); //update existing particles, but do not generate new ones
Update particles graphics:
generator.draw();
What do you think about this code?