mirror of
https://github.com/jneug/zeichenmaschine.git
synced 2026-04-14 14:43:33 +02:00
First draft of basic particle system
This commit is contained in:
85
src/main/java/schule/ngb/zm/particles/BasicParticle.java
Normal file
85
src/main/java/schule/ngb/zm/particles/BasicParticle.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
import schule.ngb.zm.Color;
|
||||||
|
import schule.ngb.zm.Vector;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
public class BasicParticle extends Particle {
|
||||||
|
|
||||||
|
protected Color color, startColor, finalColor;
|
||||||
|
|
||||||
|
|
||||||
|
public BasicParticle() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicParticle(Color startColor) {
|
||||||
|
this(0, startColor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicParticle(Color startColor, Color finalColor) {
|
||||||
|
this(0, startColor, finalColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicParticle( int pLifetime ) {
|
||||||
|
super(pLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicParticle( int pLifetime, Color startColor, Color finalColor ) {
|
||||||
|
super(pLifetime);
|
||||||
|
|
||||||
|
this.color = startColor;
|
||||||
|
this.startColor = startColor;
|
||||||
|
this.finalColor = finalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor( Color pColor ) {
|
||||||
|
this.color = pColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getStartColor() {
|
||||||
|
return startColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartColor( Color pStartColor ) {
|
||||||
|
this.startColor = pStartColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getFinalColor() {
|
||||||
|
return finalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFinalColor( Color pFinalColor ) {
|
||||||
|
this.finalColor = pFinalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void spawn( Vector pPosition, Vector pVelocity ) {
|
||||||
|
super.spawn(pPosition, pVelocity);
|
||||||
|
this.color = this.startColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update( double delta ) {
|
||||||
|
super.update(delta);
|
||||||
|
|
||||||
|
if( startColor != null && finalColor != null ) {
|
||||||
|
double t = 1.0 - lifetime / maxLifetime;
|
||||||
|
this.color = Color.interpolate(startColor, finalColor, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw( Graphics2D graphics ) {
|
||||||
|
if( this.color != null ) {
|
||||||
|
graphics.setColor(this.color.getJavaColor());
|
||||||
|
graphics.fillOval((int) position.x, (int) position.y, 6, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
import schule.ngb.zm.Color;
|
||||||
|
|
||||||
|
public class BasicParticleFactory implements ParticleFactory {
|
||||||
|
|
||||||
|
|
||||||
|
private final Color startColor;
|
||||||
|
|
||||||
|
private final Color finalColor;
|
||||||
|
|
||||||
|
private final int maxLifetime = 50;
|
||||||
|
|
||||||
|
public BasicParticleFactory() {
|
||||||
|
this.startColor = new Color(128, 128, 129);
|
||||||
|
this.finalColor = new Color(128, 128, 129, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicParticleFactory( Color startColor, Color finalColor ) {
|
||||||
|
this.startColor = startColor;
|
||||||
|
this.finalColor = finalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxLifetime() {
|
||||||
|
return maxLifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Particle createParticle() {
|
||||||
|
return new BasicParticle(maxLifetime, startColor, finalColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
64
src/main/java/schule/ngb/zm/particles/Particle.java
Normal file
64
src/main/java/schule/ngb/zm/particles/Particle.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
import schule.ngb.zm.Drawable;
|
||||||
|
import schule.ngb.zm.Updatable;
|
||||||
|
import schule.ngb.zm.Vector;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class Particle extends PhysicsObject implements Updatable, Drawable {
|
||||||
|
|
||||||
|
protected double maxLifetime = 0;
|
||||||
|
|
||||||
|
protected double lifetime = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public Particle() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Particle( int pLifetime ) {
|
||||||
|
super();
|
||||||
|
maxLifetime = pLifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn( Vector pPosition, Vector pVelocity ) {
|
||||||
|
lifetime = maxLifetime;
|
||||||
|
position = pPosition.copy();
|
||||||
|
velocity = pVelocity.copy();
|
||||||
|
acceleration = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return lifetime > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVisible() {
|
||||||
|
return isActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLifetime() {
|
||||||
|
return lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLifetime( double pLifetime ) {
|
||||||
|
this.lifetime = pLifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getMaxLifetime() {
|
||||||
|
return maxLifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxLifetime( double pMaxLifetime ) {
|
||||||
|
this.maxLifetime = pMaxLifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update( double delta ) {
|
||||||
|
super.update(delta);
|
||||||
|
// lifetime -= delta;
|
||||||
|
lifetime -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
172
src/main/java/schule/ngb/zm/particles/ParticleEmitter.java
Normal file
172
src/main/java/schule/ngb/zm/particles/ParticleEmitter.java
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
|
||||||
|
import schule.ngb.zm.Drawable;
|
||||||
|
import schule.ngb.zm.Updatable;
|
||||||
|
import schule.ngb.zm.Vector;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
public class ParticleEmitter implements Updatable, Drawable {
|
||||||
|
|
||||||
|
protected ParticleFactory particleFactory;
|
||||||
|
|
||||||
|
private int particlesPerFrame;
|
||||||
|
|
||||||
|
private int particleLifetime = 180;
|
||||||
|
|
||||||
|
private Particle[] particles;
|
||||||
|
|
||||||
|
private boolean active = false;
|
||||||
|
|
||||||
|
private Particle nextParticle;
|
||||||
|
|
||||||
|
public Vector position;
|
||||||
|
|
||||||
|
public Vector direction = new Vector();
|
||||||
|
|
||||||
|
public int angle = 0;
|
||||||
|
|
||||||
|
public double randomness = 0.0;
|
||||||
|
|
||||||
|
// private Vortex vortex = null;
|
||||||
|
|
||||||
|
public ParticleEmitter( double pX, double pY, int pParticlesPerFrame, ParticleFactory pFactory ) {
|
||||||
|
this.position = new Vector(pX, pY);
|
||||||
|
this.particlesPerFrame = pParticlesPerFrame;
|
||||||
|
this.particleFactory = pFactory;
|
||||||
|
|
||||||
|
// Create particle pool
|
||||||
|
this.particles = new Particle[particlesPerFrame * pFactory.getMaxLifetime()];
|
||||||
|
this.direction = Vector.random(8, 16).setLength(100);
|
||||||
|
|
||||||
|
// vortex = new Vortex(position.copy().add(-10, -10), -.2, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVisible() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
// Partikel initialisieren
|
||||||
|
for( int i = 0; i < particles.length; i++ ) {
|
||||||
|
particles[i] = particleFactory.createParticle();
|
||||||
|
}
|
||||||
|
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
for( int i = 0; i < particles.length; i++ ) {
|
||||||
|
particles[i].setLifetime(0);
|
||||||
|
particles[i] = null;
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Particle getNextParticle() {
|
||||||
|
// TODO: improve by caching next particle
|
||||||
|
for( Particle p : particles ) {
|
||||||
|
if( p != null && !p.isActive() ) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void emitParticle() {
|
||||||
|
int ppf = particlesPerFrame;
|
||||||
|
Particle nextParticle = getNextParticle();
|
||||||
|
while( ppf > 0 && nextParticle != null ) {
|
||||||
|
// TODO: (ngb) randomize lifetime of particles in Factory?
|
||||||
|
// int pLeben = (int) random(particleLifetime);
|
||||||
|
// p.lifetime = pLeben;
|
||||||
|
// p.maxLifetime = pLeben;
|
||||||
|
|
||||||
|
double rotation = (angle / 2.0) - (int) (Math.random() * angle);
|
||||||
|
Vector velocity = direction.copy().rotate(rotation);
|
||||||
|
velocity.scale(random());
|
||||||
|
|
||||||
|
nextParticle.spawn(this.position, velocity);
|
||||||
|
nextParticle = getNextParticle();
|
||||||
|
ppf -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update( double delta ) {
|
||||||
|
emitParticle();
|
||||||
|
|
||||||
|
boolean _active = false;
|
||||||
|
for( Particle particle : particles ) {
|
||||||
|
if( particle != null ) {
|
||||||
|
if( particle.isActive() ) {
|
||||||
|
// if( vortex != null ) {
|
||||||
|
// vortex.attract(particle);
|
||||||
|
// }
|
||||||
|
particle.update(delta);
|
||||||
|
_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.active = _active;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double random() {
|
||||||
|
return 1.0 - (Math.random() * randomness);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double random( double pZahl ) {
|
||||||
|
return pZahl * random();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw( Graphics2D graphics ) {
|
||||||
|
java.awt.Color current = graphics.getColor();
|
||||||
|
for( Particle particle : particles ) {
|
||||||
|
if( particle != null ) {
|
||||||
|
particle.draw(graphics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if( vortex != null ) {
|
||||||
|
// graphics.setColor(java.awt.Color.BLACK);
|
||||||
|
// double vscale = (4 * vortex.scale);
|
||||||
|
// graphics.fillOval((int) (vortex.position.x - vscale * .5), (int) (vortex.position.y - vscale * .5), (int) vscale, (int) vscale);
|
||||||
|
// }
|
||||||
|
graphics.setColor(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Vortex {
|
||||||
|
|
||||||
|
Vector position;
|
||||||
|
|
||||||
|
double speed = 1.0, scale = 1.0;
|
||||||
|
|
||||||
|
public Vortex( Vector pPosition, double pSpeed, double pScale ) {
|
||||||
|
this.position = pPosition.copy();
|
||||||
|
this.scale = pScale;
|
||||||
|
this.speed = pSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attract( Particle pPartikel ) {
|
||||||
|
Vector diff = Vector.sub(pPartikel.position, this.position);
|
||||||
|
double dx = -diff.y * this.speed;
|
||||||
|
double dy = diff.x * this.speed;
|
||||||
|
double f = 1.0 / (1.0 + (dx * dx + dy * dy) / scale);
|
||||||
|
|
||||||
|
pPartikel.position.x += (diff.x - pPartikel.velocity.x) * f;
|
||||||
|
pPartikel.position.y += (diff.y - pPartikel.velocity.y) * f;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
public interface ParticleFactory {
|
||||||
|
|
||||||
|
Particle createParticle();
|
||||||
|
|
||||||
|
int getMaxLifetime();
|
||||||
|
|
||||||
|
}
|
||||||
69
src/main/java/schule/ngb/zm/particles/PhysicsObject.java
Normal file
69
src/main/java/schule/ngb/zm/particles/PhysicsObject.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
import schule.ngb.zm.Updatable;
|
||||||
|
import schule.ngb.zm.Vector;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class PhysicsObject implements Updatable {
|
||||||
|
|
||||||
|
protected Vector position, velocity, acceleration;
|
||||||
|
|
||||||
|
protected double mass = 1.0;
|
||||||
|
|
||||||
|
|
||||||
|
public PhysicsObject() {
|
||||||
|
position = new Vector();
|
||||||
|
velocity = new Vector();
|
||||||
|
acceleration = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PhysicsObject( Vector pPosition ) {
|
||||||
|
position = pPosition.copy();
|
||||||
|
velocity = new Vector();
|
||||||
|
acceleration = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getAcceleration() {
|
||||||
|
return acceleration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAcceleration( Vector pAcceleration ) {
|
||||||
|
this.acceleration = pAcceleration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getMass() {
|
||||||
|
return mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMass( double pMass ) {
|
||||||
|
this.mass = pMass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition( Vector pPosition ) {
|
||||||
|
this.position = pPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getVelocity() {
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVelocity( Vector pVelocity ) {
|
||||||
|
this.velocity = pVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accelerate( Vector pAcceleration ) {
|
||||||
|
acceleration.add(Vector.div(pAcceleration, mass));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update( double delta ) {
|
||||||
|
velocity.add(acceleration);
|
||||||
|
position.add(Vector.scale(velocity, delta));
|
||||||
|
acceleration.scale(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
src/test/java/schule/ngb/zm/particles/ParticleExample.java
Normal file
36
src/test/java/schule/ngb/zm/particles/ParticleExample.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package schule.ngb.zm.particles;
|
||||||
|
|
||||||
|
import schule.ngb.zm.Zeichenmaschine;
|
||||||
|
import schule.ngb.zm.layers.DrawableLayer;
|
||||||
|
|
||||||
|
public class ParticleExample extends Zeichenmaschine {
|
||||||
|
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
new ParticleExample();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParticleExample() {
|
||||||
|
super(400, 400, "ZM: Particles");
|
||||||
|
}
|
||||||
|
|
||||||
|
ParticleEmitter pgen;
|
||||||
|
|
||||||
|
public void setup() {
|
||||||
|
pgen = new ParticleEmitter(
|
||||||
|
200, 200, 1,
|
||||||
|
new BasicParticleFactory()
|
||||||
|
);
|
||||||
|
pgen.randomness = .5;
|
||||||
|
pgen.angle = 45;
|
||||||
|
DrawableLayer drawables = new DrawableLayer();
|
||||||
|
addLayer(drawables);
|
||||||
|
drawables.add(pgen);
|
||||||
|
pgen.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update( double delta ) {
|
||||||
|
pgen.update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user