/** *

SpaceBoxes_by_spxl

*

by subpixel

*

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:

* */ /** * 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; }