Sonntag, 6. September 2009

Initial Draft

Chunk 52

A Curve Example 2

The previous chapter used acceleration and deceleration to show some interesting effects that can be achieved with curves. In this chapter we will continue with curves and have a bit of fun with some very basic physics using a simple fireworks simulation. Fireworks are shot up in to the air using an initial force which is acted on by gravity causing them to decelerate as they gain height. The firework then explodes throwing out a multitude of particles each of which are also acted on from the force of the explosion and gravity. This should provide us with an interesting algorithm to show some rather pretty patterns.

Fireworks

First of all let use have a look at which elements and variables will be required to implement a firework simulation. Without gravity, the firework would continue unhindered on a streight line trajectory, so adding it will introduce a nice believable projectile trajectory to the simulation. The firework will require an initial force to launch it followed by a simple time delay as to when the explosion should take place. Initially the firework will draw the launching rocket as a particle, once the explosion occurs, the firework stops drawing the rocket and instead draws each of the explosion particles.

Basic Physics

There are some extremelly complicated formulas for working out projectile trajectories which take into account wind resistence and all sorts of other variables. In order to keep the simulation simple, the fireworks code uses a very simple algorithm for working out the x and y coordinates of a particle at a given time.

x = (velocity * cos(angle) * time)
y = (velocity * sin(angle) * time) - (½ gravity * time²)

The x and y coordinates given from this formula assume that the projectile was initially at 0, 0. This is not the case for either the rocket or the particles. The rocket will be launched from the middle of the ground of the screen. Processing uses the typical Java representation of 0, 0 being located at the top left of the window so our rocket will initially be launched from a point 200 pixels left and 400 pixels down. The explosion particles will have their initial position at the last position of the rocket.

Gravity
Firework Initial Thrust
Firework Trajectory
Firework Explossion Delay
Number Of Particles
Particle Time To Live
Particle Trajectory

OO Principles

Although this section does not primarily deal with Object Oriented principles, the fireworks program will make use of a couple of OO design principals in order to reduce the amount of code through reuse. The fireworks code is split into two main classes, namely the 'Rocket' class and secondly the 'Particle' class. The rocket class uses composition and contains a main particle, the rocket, and an array of particles which are part of the explosion. Using this model allows both the rocket and the particles to be drawn using the same code.



float gravity = 9;
Firework firework = new Firework();

void setup() {
background(255);
smooth();
size(400,400);
frameRate(30);
}

void draw() {
//background(255);
smooth();

if (!firework.isAlive()) {
firework = new Firework();
}
firework.draw();
}

/**
* Represent a rocket together with its explosion particles.
**/
class Firework {
Particle rocket;
Particle[] particles;
boolean explosion = false;
float explosionOffset;

Firework() {
rocket = new Particle(
200, 400,
random(80, 100), random(1.4, 1.8),
random(0, 200), random(0, 200), random(0, 200));

particles = new Particle[(int) random(80, 200)];
explosionOffset = random(2.5, 4.5);
}

void draw() {
strokeWeight(2);

if (explosion) {
int i = 0;
for (i = 0; i < particles.length; i++) {
particles[i].fadeOut();
particles[i].draw();
}

} else {
if (rocket.particleTime > explosionOffset) {
explosion = true;
int i = 0;
for (i = 0; i < particles.length; i++) {

particles[i] = new Particle(
rocket.initialX + rocket.dx, rocket.initialY - rocket.dy,
random(20, 40), random(0.5, 2.5),
random(200, 255), random(100, 200), random(0, 255));
}
}
rocket.draw();
}
}

boolean isAlive() {
boolean alive = !explosion;
int i;
for (i = 0; i < particles.length; i++) {
if (particles[i] != null) {
alive = alive || particles[i].isAlive();
}
}
return alive;
}
}

/**
* Represent a particle which has a trajectory.
**/
class Particle {
float dy = 0;
float dx = 0;
float particleTime = 0;
float timeToLive = random(15, 50);
float velocity, angle, initialX, initialY, initialisationTime;
float colourRed, colourGreen, colourBlue;

/**
* @param x Initial X position.
* @param y Initial Y position.
* @param v Initial velocity.
* @param a Initial angle.
* @param r Initial red colour.
* @param g Initial green colour.
* @param b Initial blue colour.
**/
Particle(float x, float y, float v, float a, float r, float g, float b) {
velocity = v;
angle = a;
initialX = x;
initialY = y;
colourRed = r;
colourGreen = g;
colourBlue = b;
}

/**
* Cause the colours to tend towards white (255, 255, 255).
**/
void fadeOut() {
colourRed++;
colourGreen++;
colourBlue++;
}

void draw() {
// Here we use the trajectory formuala. Note that the cos and sin functions expect angle in radians.
dx = velocity * cos(angle) * particleTime;
dy = (velocity * sin(angle) * particleTime) - (0.5 * gravity * particleTime * particleTime);

stroke(colourRed, colourGreen, colourBlue);
point(initialX + dx, initialY - dy);

particleTime = particleTime + 0.1;
timeToLive--;
}

/**
* Check if the particle is alive and should be drawn.
**/
boolean isAlive() {
return timeToLive > 0;
}
}

Keine Kommentare:

Kommentar veröffentlichen