Scene world; Mass nearMass = null; boolean bgstat = true; boolean trails=false; int MAX_PHYSICSOBJECTS = 20000; int ticks=0; int wallthresh=0; int wallright=0; int walltop=0; int wallbottom=0; boolean mouseIsDragging = false; Vector drawnRects; boolean executing_loop_now = false; Sonia sonia; Sample []tinks; int tinkCounter = 0; public void setup(){ drawnRects = new Vector(); nearMass = null; size(640,480); world = new Scene(); bgstat = true; noStroke(); rect(0,0,width,height); wallright=0; walltop=0; wallbottom=0; sonia = new Sonia(); sonia.start(this,22050); tinks = new Sample[10]; for(int i=0;i<10;i++){ tinks[i] = new Sample("tink1.wav"); } } void keyPressed(){ //wait til loop is down first while(executing_loop_now); drawnRects = new Vector(); world = new Scene(); } void playTink(float rate){ tinks[tinkCounter].setRate(rate); tinks[tinkCounter].play(); tinkCounter++; if(tinkCounter>=10){ tinkCounter = 0; } } void mousePressed(){ //world = new Scene(); drawnRects = new Vector(); //add a new rect to the rects, //but leave it open because we're still drawing it. float []r = new float[4]; r[0] = mouseX; r[1] = mouseY; drawnRects.add(r); mouseIsDragging = true; } public void mouseReleased(){ mouseIsDragging = false; float [] r = (float[])drawnRects.elementAt(0); world.createBox(r[0],r[1],r[2]-r[0],r[3]-r[1]); } void loop(){ executing_loop_now = true; long mill = millis(); background(#000000); if(nearMass!=null){ //Mass m1 = (Mass)world.getMasses().elementAt(0); nearMass.p.x = mouseX; nearMass.p.y = mouseY; nearMass.v.x = nearMass.v.y = nearMass.v.z = 0; } world.step(); rectMode(CENTER_DIAMETER); stroke(0); noFill(); Spring thisSpring; int limiter = 0; if(world.all.size()>MAX_PHYSICSOBJECTS){ limiter=world.all.size()-MAX_PHYSICSOBJECTS; } for(int i=world.all.size()-1;i>=limiter;i--){ if(world.get(i) instanceof Spring){ thisSpring = (Spring)world.get(i); //call proce55ing graphics if(thisSpring.visible){ stroke(255); line((int)thisSpring.mass1.p.x,(int)thisSpring.mass1.p.y, (int)thisSpring.mass2.p.x,(int)thisSpring.mass2.p.y); } } } if(mouseIsDragging){ //draw the editable rects. for(int i=0;i (restLength*3)/2) { len = (restLength*3)/2; } // calculate tension based on springiness and length of spring tension = springConstant * ((restLength-len)/restLength); fX = tension * (lenX/len); fY = tension * (lenY/len); fZ = tension * (lenZ/len); // apply the spring tension force to the two masses mass1.applyForce(-fX, -fY, -fZ); mass2.applyForce(fX, fY, fZ); } } ////////////////////////////////////////////////////////////////// class Mass implements Steppable{ // Constants for all Masses (gravity is in Physics3D too) public static final double gravity = 10; public static final double DT = 20.01;//time step = 1/100 sec or 10 millis public static final double accelPerDT = gravity * 0.01; // public int ID; // index of this mass in array of masses public double m; // weight public Vector3D p; // contains screen x,y and as x,y,z vector public Vector3D v; // xyz velocity public boolean frozen; // mass can't move // // 'Register' vars for calculations double mag; // added by added by jtnimoy protected static final int selAttrib = 0; public Mass(double mass, double x, double y, double z, double Vx, double Vy, double Vz){ frozen = false; m = mass; p = new Vector3D(x, y, z); // position v = new Vector3D(Vx, Vy, Vz); // velocity } public void applyForce(double fx, double fy, double fz){ v.x += (DT * fx) / m; v.y += (DT * fy) / m; v.z += (DT * fz) / m; } public void step(){ if(frozen){ v.x = v.y = v.z = 0.0; return; } v.y += accelPerDT; limit(); p.x += v.x * DT; p.y += v.y * DT; p.z += v.z * DT; //------and now, a basic rectangular 2D wall "bouncing" float freqfactor = 5000; float soundthresh = 0.8; if(p.y > height-wallbottom){ p.y = (height-wallbottom)-Math.random(); if(v.x+v.z+v.y>soundthresh){ playTink((float)(v.x+v.z+v.y)*freqfactor); } v.x = v.z = v.y = 0.0; } if(p.y < 0.0){ p.y = Math.random(); if(v.x+v.z+v.y>soundthresh){ playTink((float)(v.x+v.z+v.y)*freqfactor); }v.x = v.z = v.y = 0.0; } if(p.x > width){ p.x = width-Math.random(); if(v.x+v.z+v.y>soundthresh){ playTink((float)(v.x+v.z+v.y)*freqfactor); }v.x = v.z = v.y = 0.0; } if(p.x < wallthresh){ p.x = wallthresh;//Math.random(); if(v.x+v.z+v.y>soundthresh){ playTink((float)(v.x+v.z+v.y)*freqfactor); }v.x = v.z = v.y = 0.0; } //println(v.x+v.z+v.y); } public Mass duplicate(){//was this added by jtnimoy? return new Mass(m, p.x, p.y, p.z, v.x, v.y, v.z); } private void limit(){ mag = v.x * v.x + v.y * v.y + v.z * v.z; if(mag > 10.0){//this was originally 10000D in Mark's code double vh = Math.sqrt(mag / 10.0);//so was this v.x /= vh; v.y /= vh; v.z /= vh; } } } ///////////////////////////////////////////////////////////////////// class Vertex extends Vector3D { public int sx; public int sy; public boolean visible; public Color reflectColour = new Color(0x222222); public Vertex(double d, double d1, double d2) { super(d, d1, d2); visible = false; } public Vertex(Vector3D v) { super(v.x, v.y, v.z); visible = false; } } ///////////////////////////////////////////////////////////////////// class Vector3D { public double x; public double y; public double z; public Vector3D(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public double angle(Vector3D v) { return Math.acos(cosAngle(v)); } public double cosAngle(Vector3D v) { double a= Math.sqrt(dotProduct(this)); double b = Math.sqrt(v.dotProduct(v)); double c = dotProduct(v); return c / (a * b); } public Vector3D crossProduct(Vector3D v) { return new Vector3D(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } public double dotProduct(Vector3D v) { return x * v.x + y * v.y + z * v.z; } public double magnitude() { return Math.sqrt(dotProduct(this)); } public Vector3D minus(Vector3D v) { return new Vector3D(x - v.x, y - v.y, z - v.z); } public Vector3D plus(Vector3D v) { return new Vector3D(x + v.x, y + v.y, z + v.z); } public void scale(double s) { x *= s; y *= s; z *= s; } public void subtract(Vector3D v) { x -= v.x; y -= v.y; z -= v.z; } } ////////////////////////////////////////////////////////////////// class Scene{ public Vector all; private boolean paused; public Scene(){ all = new Vector(); paused = false; } // add an array of springs and masses to scene public synchronized void add(Steppable[] obj){ for(int i = 0; i < obj.length; i++){ all.addElement(obj[i]); } } // add one spring or mass to scene public synchronized void add(Steppable o){ all.addElement(o); } public synchronized Steppable get(int i){ return (Steppable)all.elementAt(i); } public synchronized void remove(Steppable o){ all.removeElement(o); } ////////////////////////////////////////////////////////////// // find nearest mass to mouse click // points hold screen x,y coords and spatial x,y,z so we // can map screen to 3D space easily public Mass nearestMass(int x, int y) { Mass mass = null; double maxDist = 1000000; for(int i = 0; i < size(); i++){ if(get(i) instanceof Mass) { Mass m1 = (Mass)get(i); double dx = (x - m1.p.x); double dy = (y - m1.p.y); dx *= dx; dy *= dy; double dist = 0; dist = Math.sqrt(dx+dy); if(dist < maxDist){ maxDist = dist; mass = m1; } } } return mass; } public void step(){ if(!paused){ int limiter = 0; if(all.size()>MAX_PHYSICSOBJECTS){ limiter=all.size()-MAX_PHYSICSOBJECTS; } for(int i=all.size()-1; i >= limiter; i--){ ((Steppable)all.elementAt(i)).step(); } } } public synchronized int size() { return all.size(); } public void togglePaused() { paused = !paused; } public Vector getMasses(){ Vector vc = new Vector(); for(int i=0;iSteppable interface should be implemented by any * class whose instances can take steps, ie. animations, physics * simulations, timers. The class must define a method of no arguments * called step. *

* This interface provides a common protocol for objects that * can be driven by an Engine. *

* * @see Engine */ public interface Steppable { /** * An Engine calls the step function while executing. *

* The method step may contain any code. */ public abstract void step(); } // the end