/**
*
SpaceBoxes_by_spxl
*
* Version 1.1, 2009-01-18
*
* Original idea and code ased on Falling Box by takumi
* Flying through an asteroid field, kind of.
* Autopilot (no controls!)
* Keys:
*
* - [space] toggle paused
* - [a] auto mode (randomly toggles background)
* - [b] toggle background
* - [r] toggle regular/random block sizes
* - [s] toggle scene spin
* - [t] toggle objects tumble
* - [LEFT] [RIGHT] [UP] [DOWN] change scene orientation
* - [HOME] [END] reset scene orientation
* - [<] [>] [/] slow down, speed up, reset speed
*
*/
/**
* 2009-01-18 Version 1.1 by subpixel
* - Code tidy.
* - User controls: toggle spin, toggle tumble, scene orientation, timewarp.
*/
//import processing.opengl.*; // Only need if you want to use OPENGL mode
// Oldschool / basic use of arrays carried over from takumi's code
// At least 1-dimensional arrays are fast to access
final int numFliers = 96; // Number of flying objects
// Position
float[] X = new float[numFliers];
float[] Y = new float[numFliers];
float[] Z = new float[numFliers];
// Velocity
float[] vX = new float[numFliers];
float[] vY = new float[numFliers];
float[] vZ = new float[numFliers];
// Size (of central box)
int[] s = new int[numFliers];
// Rotation
float[] thetaX = new float[numFliers];
float[] thetaY = new float[numFliers];
float[] thetaZ = new float[numFliers];
// Angular velocity
float[] omegaX = new float[numFliers];
float[] omegaY = new float[numFliers];
float[] omegaZ = new float[numFliers];
// Size of side boxes
int[] s1 = new int[numFliers];
int[] s2 = new int[numFliers];
int[] s3 = new int[numFliers];
int[] s4 = new int[numFliers];
int[] s5 = new int[numFliers];
int[] s6 = new int[numFliers];
// Distance of (centres of) side boxes from (centre of) central box
float[] d1 = new float[numFliers];
float[] d2 = new float[numFliers];
float[] d3 = new float[numFliers];
float[] d4 = new float[numFliers];
float[] d5 = new float[numFliers];
float[] d6 = new float[numFliers];
PImage bg; // To hold a background image if you want one
int bgx; // Size information for scaling background image
int bgy; // Size information for scaling background image
float sceneThetaX = 0; // Current scene rotation
float sceneThetaY = 0; // Current scene rotation
float sceneThetaZ = 0; // Current scene rotation
float sceneOmegaX = 0; // Angular velocity for scene rotation
float sceneOmegaY = 0; // Angular velocity for scene rotation
float sceneOmegaZ = 0; // Angular velocity for scene rotation
float spinDamping = 0.92; // Drag.damping factor for scene rotation
// User controlled parameters
boolean ctrlPaused = false; // Want to be able to toggle paused/unpaused
boolean ctrlAuto = false; // Auto mode?
boolean ctrlBackground = true; // Show background?
boolean ctrlRegular = false; // Regular size/spacing or random?
boolean ctrlSpinScene = true; // Spin the scene?
boolean ctrlTumble = true; // Objects tumble as they fly?
float timeWarp = 1.0; // 1 is not warped. 0 is stopped. -1 is reversed. 2 is double speed.
int autoCountdown = 0; // Frames to go until next random action (if auto==true)
// ------------------------------------------------------------
// Setup method
// ------------------------------------------------------------
void setup(){
// size(screen.width, screen.height >> 1, OPENGL); // Fullscreen anyone? :o)
size(720, 320, P3D); // Applet-friendly dimensions
frameRate(30);
colorMode(HSB, 100);
// Prepare the background image and work out some sizing information
bg = loadImage("bg.png"); // Load a background image
int windowSize = max(width, height);
int imageSize = min(bg.width, bg.height);
int factor = ceil(2.5 * float(windowSize) / float(imageSize));
bgx = bg.width * factor;
bgy = bg.height * factor;
// Initialise all of the flying objects
for(int i = 0; i < numFliers; i++)
{
randomise(i);
}
}
// ------------------------------------------------------------
// Draw method
// ------------------------------------------------------------
void draw()
{
background(0);
// Camera at (0, 0, 2000) looking at the origin (0, 0, 0), Y-axis is "up"
// This puts (0, 0, z) at the centre of the window
camera(0, 0, 2000, 0, 0, 0, 0, 1, 0);
if (ctrlSpinScene) // Spin the entire scene
{
// Take a noise sample based on time elapsed. Manipulate the [0,1) value
// to a [-0.5, 0.5) value, scale it down a bit and use that as an angular
// acceleration.
sceneOmegaZ = (sceneOmegaZ + (noise(millis()*0.001)-0.5)*0.03) * 0.92;
}
// Apply a drag/damping factor to the spin so we don't get too dizzy... :o)
sceneOmegaX *= spinDamping;
sceneOmegaY *= spinDamping;
sceneOmegaZ *= spinDamping;
sceneThetaX += sceneOmegaX;
sceneThetaY += sceneOmegaY;
sceneThetaZ += sceneOmegaZ;
rotateX(sceneThetaX); // Orient the scene
rotateY(sceneThetaY); // Orient the scene
rotateZ(sceneThetaZ); // Orient the scene
if (ctrlAuto) // Automatic background toggle
{
autoCountdown--;
if (autoCountdown <= 0)
{
toggleBackground();
resetAutoCountdown();
}
}
if (ctrlBackground) // Show background image?
{
image(bg, -bgx, -bgy, bgx << 1, bgy << 1);
}
// Set up lighting for the scene
// A light pointing straight up and another pointing straight down
directionalLight(51, 102, 126, 0, 1, 0);
directionalLight(10, 20, 30, 0, -1, 0);
for (int i = 0; i < numFliers; i++)
{
pushMatrix();
translate(X[i], Y[i], Z[i]); // Central box position
rotateX(thetaX[i]); // Orientation
rotateY(thetaY[i]); // ...
rotateZ(thetaZ[i]); // ...
// Central box
// Don't stroke edges. Fill 100 (out of 100).
noStroke();
fill(100); // White, 100% opacity
box(s[i]);
// Surrounding boxes
translate(d1[i], 0, 0); // Go right
box(s1[i]);
translate(-d1[i] - d2[i], 0, 0); // Go back to centre and left
box(s2[i]);
translate(d2[i], d3[i], 0); // Go back to centre and "down" (along -Y axis)
box(s3[i]);
translate(0, -d3[i] - d4[i], 0); // Go back to centre and up
box(s4[i]);
translate(0, d4[i], d5[i]); // Go back to centre and "in front"
box(s5[i]);
translate(0, 0, -d5[i] - d6[i]); // Go back to centre and "behind"
box(s6[i]);
popMatrix();
// Update position and rotation
if(Z[i] > 2000) // Flown past us ("through the screen") already
{
randomise(i);
}
else
{
// Move (constant velocity)
X[i] += vX[i] * timeWarp;
Y[i] += vY[i] * timeWarp;
Z[i] += vZ[i] * timeWarp;
if (ctrlTumble) // Rotate
{
thetaX[i] += omegaX[i] * timeWarp;
thetaY[i] += omegaY[i] * timeWarp;
thetaZ[i] += omegaZ[i] * timeWarp;
}
}
}
}
// ------------------------------------------------------------
// Initialise flying object with array index i
// ------------------------------------------------------------
void randomise(int i)
{
X[i] = 0;
Y[i] = 0;
Z[i] = -random(1000);
vX[i] = random(-1, 1);
vY[i] = random(-1, 1);
vZ[i] = random(10) + 0.2;
thetaX[i] = random(TWO_PI);
thetaY[i] = random(TWO_PI);
thetaZ[i] = 0; // Already as (dis-)oriented as one can be from 2 axes. :o)
omegaX[i] = random(0.01, 0.1);
omegaY[i] = random(0.01, 0.1);
omegaZ[i] = 0; // Spinning on a 3rd axis doesn't help.. gives strange motion
int b = int(random(1, 4)) * 10;
int b_2 = b >> 1;
s[i] = b; // Set size of central box
if (ctrlRegular)
{
s1[i] = s2[i] = s3[i] = s4[i] = s5[i] = s6[i] = b_2; // Half central box size
d1[i] = d2[i] = d3[i] = d4[i] = d5[i] = d6[i] = b; // Spaced by central box size
}
else
{
// Size of 6 boxes surrounding central box
s1[i] = int(random(b_2, b));
s2[i] = int(random(b_2, b));
s3[i] = int(random(b_2, b));
s4[i] = int(random(b_2, b));
s5[i] = int(random(b_2, b));
s6[i] = int(random(b_2, b));
// Distance of 6 surrounding boxes from central box (measured from centres)
d1[i] = b_2 + int(random(s1[i] >> 1, s1[i] << 1));
d2[i] = b_2 + int(random(s2[i] >> 1, s2[i] << 1));
d3[i] = b_2 + int(random(s3[i] >> 1, s3[i] << 1));
d4[i] = b_2 + int(random(s4[i] >> 1, s4[i] << 1));
d5[i] = b_2 + int(random(s5[i] >> 1, s5[i] << 1));
d6[i] = b_2 + int(random(s6[i] >> 1, s6[i] << 1));
}
}
// ------------------------------------------------------------
// Handle keyboard input
// ------------------------------------------------------------
void keyPressed()
{
switch(key)
{
case CODED: codedKeyPressed(keyCode);
break;
case ' ': togglePaused();
break;
case 'A':
case 'a': toggleAuto();
break;
case 'B':
case 'b': toggleBackground();
break;
case 'R':
case 'r': toggleRegular();
break;
case 'S':
case 's': toggleSpinScene();
break;
case 'T':
case 't': toggleTumble();
break;
case '<':
case ',': slowDown();
break;
case '>':
case '.': speedUp();
break;
case '?':
case '/': speedReset();
break;
default: println("keyPressed(): key = [" + key + "]"); // Maybe handy later
break;
}
}
void codedKeyPressed(int code)
{
final int END = 35;
final int HOME = 36;
switch (code)
{
case UP: sceneOmegaX += 0.05;
break;
case DOWN: sceneOmegaX -= 0.05;
break;
case LEFT: sceneOmegaY -= 0.05;
break;
case RIGHT: sceneOmegaY += 0.05;
break;
case END:
case HOME: sceneOmegaX = sceneOmegaY = 0;
sceneThetaX = sceneThetaY = 0;
break;
default: println("codedKeyPressed(" + code + ")"); // Maybe handy later
break;
}
}
// ------------------------------------------------------------
void togglePaused()
{
ctrlPaused = !ctrlPaused;
if (ctrlPaused)
noLoop();
else
loop();
}
void toggleAuto()
{
ctrlAuto = !ctrlAuto;
if (ctrlAuto) resetAutoCountdown();
}
void toggleBackground()
{
ctrlBackground = !ctrlBackground;
}
void toggleRegular()
{
ctrlRegular = !ctrlRegular;
}
void toggleSpinScene()
{
ctrlSpinScene = !ctrlSpinScene;
}
void toggleTumble()
{
ctrlTumble = !ctrlTumble;
}
void slowDown()
{
timeWarp -= 0.1;
}
void speedUp()
{
timeWarp += 0.1;
}
void speedReset()
{
timeWarp = 1.0;
}
// ------------------------------------------------------------
// Helper methods
// ------------------------------------------------------------
void resetAutoCountdown()
{
// Use a shorter countdown if the background isn't being shown now
autoCountdown = int(random(ctrlBackground ? 100 : 20)) + 10;
}