Smoke trails
back
Source
/* @pjs preload="rocket.png"; */
PImage rocket;
float SPEED = 4.5;
float TURN_RATE = 0.125;
float WOBBLE_LIMIT = 0.25;
float WOBBLE_SPEED = 0.75;
int SMOKE_LIFETIME = 200;
int NUMBER_OF_SMOKE_PARTICLES = 100;
int SMOKE_EMISSION_SPEED = 2;
// Create a variable called wobble that tweens back and forth between
// -WOBBLE_LIMIT and +WOBBLE_LIMIT forever
float wobble = WOBBLE_LIMIT;
float wobble_direction = 1;
float rocket_x;
float rocket_y;
float velocity_x;
float velocity_y;
float rotation;
Smoke[] smokeParticles;
int currentParticle;
int emitTimer;
// Setup the example
void setup(){
size(640, 480);
imageMode(CENTER);
smokeParticles = new Smoke[NUMBER_OF_SMOKE_PARTICLES];
for(int i = 0; i < smokeParticles.length; i++){
smokeParticles[i] = new Smoke();
}
// Load images
rocket = loadImage("rocket.png");
}
// The draw() method is called every frame
void draw(){
background(#4488cc);
// Calculate the angle from the missile to the mouse cursor game.input.x
// and game.input.y are the mouse position; substitute with whatever
// target coordinates you need.
float targetRotation = atan2(mouseY - rocket_y, mouseX - rocket_x);
// Add our "wobble" factor to the targetRotation to make the missile wobble
targetRotation += wobble;
wobble = lerp(wobble, WOBBLE_LIMIT * wobble_direction, WOBBLE_SPEED);
if(wobble == WOBBLE_LIMIT * wobble_direction)
wobble_direction *= -1;
// Gradually (this.TURN_RATE) aim the missile towards the target angle
if(rotation != targetRotation){
// Calculate difference between the current angle and targetAngle
float delta = targetRotation - rotation;
// Keep it in range from -180 to 180 to make the most efficient turns.
if(delta > PI) delta -= TWO_PI;
if(delta < -PI) delta += TWO_PI;
if(delta > 0){
// Turn clockwise
rotation += TURN_RATE;
}else{
// Turn counter-clockwise
rotation -= TURN_RATE;
}
// Just set angle to target angle if they are close
if(abs(delta) < radians(TURN_RATE)){
rotation = targetRotation;
}
}
// Calculate velocity vector based on rotation and this.SPEED
velocity_x = cos(rotation) * SPEED;
velocity_y = sin(rotation) * SPEED;
rocket_x += velocity_x;
rocket_y += velocity_y;
for(int i = 0; i < smokeParticles.length; i++){
smokeParticles[i].display();
}
emitTimer++;
if(emitTimer > SMOKE_EMISSION_SPEED){
emitTimer = 0;
smokeParticles[currentParticle].reset(rocket_x - velocity_x, rocket_y - velocity_y);
currentParticle = (currentParticle + 1) % smokeParticles.length;
}
pushMatrix();
translate(rocket_x, rocket_y);
rotate(rotation);
image(rocket, 0, 0);
popMatrix();
}
class Smoke{
float x;
float y;
float velocity_y;
int ttl;
void display(){
if(ttl <= 0)
return;
y += velocity_y;
ttl--;
pushStyle();
noStroke();
fill(255, 255, 255, (int)(255 * ( ttl / (float) SMOKE_LIFETIME)));
ellipse(x, y, 10, 10);
popStyle();
}
void reset(float x, float y){
this.x = x;
this.y = y;
this.velocity_y = random(-0.8, -0.5);
ttl = SMOKE_LIFETIME;
}
}