import java.lang.reflect.*; RectTextButton createCurveButton; RectTextButton adjustCurveButton; RectTextButton createCarButton; RectTextButton adjustCarButton; static int doNothingMode =0; static int createCurveMode =1; static int adjustCurveMode =2; static int keyFrameMode = 3; static int editDCMode = 4; static int d3mode = 5; pt constrainPt = new pt(0,0); int curAdjustCurve = -1; PImage carSprite; int curSelectedCar = -1; int mode = doNothingMode; boolean anim = false; boolean curveAnim = false; float velocityModifier =1; float framesPerTime = 400; float myTime=0; pt upleftDist, botrightDist, upleftCurve, botrightCurve; polyloop road ; boolean showCars=true; boolean editCurveMode = true; boolean isPaused = false; boolean collisionTest = true; boolean boxOnly = false; boolean firstPerson = false; PFont standardFont; AudioClip crashSound; //D3Engine d3engine = new D3Engine(); Collision collide = new Collision (); ArrayList crashanims = new ArrayList(); void setup() { size(550,550); upleftCurve = new pt (0,0); botrightCurve = new pt (width*7/8, height*4/5); upleftDist = new pt (10,height*4/5); botrightDist = new pt (width-10,height); createCurveButton = new RectTextButton ( width *7 / 8 + 10, 10, width/8 - 20, height / 10, "Create\nCurve", 14 ); adjustCurveButton = new RectTextButton ( width *7 / 8 + 10, 20+height/10, width/8 - 20, height / 10, "Adjust\nCurve", 14 ); createCarButton = new RectTextButton ( width *7 / 8 + 10, 30+2*height/10, width/8 - 20, height / 10, "Create\nCar", 14 ); adjustCarButton = new RectTextButton ( width *7 / 8 + 10, 40+3*height/10, width/8 - 20, height / 10, "Adjust\nCar", 14 ); framerate(30); carSprite = loadImage ("car.png"); road = new polyloop (ceil(botrightCurve.x),ceil(botrightCurve.y),0,0); standardFont = loadFont("ArialNarrow.vlw"); //d3engine.setup(); allocateImages ("explosion", 17); try { crashSound = newAudioClip(new URL("http://www.amromousa.com/classes/CS4496/project1/d/data/carcrash.wav")); } catch (Exception e) { e.printStackTrace(); } } void draw() { colorMode(RGB,255); background(255); stroke(255); update (); if ( mode != d3mode) { road.draw (); // separator lines stroke (0); strokeWeight (2); if ( mode == editDCMode ) line (width*7/8, 0, width*7/8, height); else line (width*7/8, 0, width*7/8, height*4/5); if ( mode != editDCMode ) line (0,height*4/5,width,height*4/5); strokeWeight(1); stroke(255); if (mode == createCurveMode ) createCurveButton.setChecked (color(255,188,188), true); else createCurveButton.setChecked (color(255,188,188), false); if (mode == adjustCurveMode ) adjustCurveButton.setChecked (color(188,255,188), true); else adjustCurveButton.setChecked (color(0,0,0), false); if (mode == keyFrameMode ) adjustCarButton.setChecked (color(188,255,188), true); else adjustCarButton.setChecked (color(0,0,0), false); createCurveButton.display(); adjustCurveButton.display(); createCarButton.display(); adjustCarButton.display(); drawCurves(); } else ; // d3engine.draw(road,firstPerson); if(anim) { animCars(!isPaused); for ( int i=0; i < crashanims.size(); ++i ) ((AniSprite) crashanims.get(i)).display(); } if ( mode != d3mode ){ if ( mousePressed == true && curSelectedCar >= 0 ) { ((Car) cars.get(curSelectedCar)).anim( false); } if (showCars) { for (int i=0, n=cars.size(); i < n; i++) { Car cur = (Car) cars.get(i); cur.drawPositions(); } } } } void animCars(boolean timeStep) { if (timeStep) { float oldTime = myTime; myTime = myTime + 1.0/framesPerTime * velocityModifier; if ( collisionTest ) { for (int i=0, n=cars.size(); i < n; i++) { ((Car) cars.get(i)).tmpUpdatePosFromTime(myTime); } if ( collide.testCollisions(cars) ) { myTime = collide.findCollisionTime(oldTime,myTime,cars); for (int i=0, n=cars.size(); i < n; i++) { ((Car) cars.get(i)).updatePosFromTime(myTime); } ArrayList collisionData = new ArrayList(); collide.getCollisionPoints (cars,collisionData); // collision not yet detected, due to floating point errors int loop = 100; while ( collisionData.size() == 0 && loop > 0 ) { loop--; myTime += 1e-5; for (int i=0, n=cars.size(); i < n; i++) { ((Car) cars.get(i)).tmpUpdatePosFromTime(myTime); } collide.getCollisionPoints (cars,collisionData); } for (int i=0, n=cars.size(); i < n; i++) { ((Car) cars.get(i)).updatePosFromTime(myTime); } for ( int i =0, sz = collisionData.size(); i < sz; i+=4) { pt col = (pt) collisionData.get(i); Car car1 = (Car) collisionData.get(i+1); Car car2 = (Car) collisionData.get(i+2); pt normal = (pt) collisionData.get(i+3); collide.handleCollision ( car1,car2,col,normal,myTime); AniSprite crash = new AniSprite(col); crashanims.add(crash); crashSound.play(); } myTime = myTime + 1.0/framesPerTime * velocityModifier; } } for (int i=0, n=cars.size(); i < n; i++) { ((Car) cars.get(i)).updatePosFromTime(myTime); } } for (int i=0, n=cars.size(); i < n; i++) { Car cur = (Car) cars.get(i); if (curveAnim) { cur.updateVelocityFromCurvature(); cur.bc.travelDist += cur.bc.velocity * velocityModifier; cur.anim(true); return; } if ( mode != d3mode ) cur.anim(true); else ;//cur.draw3DCar(boxOnly); if ( cur.poses.size() != 1) { DistanceCurve dc = ((Car) cars.get(i)).dc; pt val = new pt(0,0); pt tangent = new pt(0,0); dc.sampleTime(myTime, val,tangent); mapPoint(val); if (curSelectedCar == i) { stroke (188,0,188); line(0,val.y,width,val.y); line(val.x,height,val.x,height*4/5); } } } } void drawCurves() { boolean midPoint = true; if ( mode == createCurveMode ) midPoint = false; for (int i=0, n=cars.size(); i < n; i++) { Car cur = (Car) cars.get(i); cur.drawCurve (midPoint); if ( mode == editDCMode) { fill (255,200); stroke (255,200); rect (0,0, width*4/5,height); } if ( i == curSelectedCar ) cur.drawSpeedCurve (midPoint); } } void keyPressed () { if (mode == createCurveMode) { if ( key == ENTER ) { BezierCurve b = ((Car) cars.get(cars.size()-1)).bc; b.calcLength(true); Car c = ((Car) cars.get(cars.size()-1)); c.rebuildSpeedCurve (); mode = doNothingMode; } if ( key == BACKSPACE ) { cars.remove ( cars.size() -1 ); mode = doNothingMode; } } if ( mode == doNothingMode || mode == d3mode) { if (key == 'g' || key == 'G') { anim = !anim; for ( int i =0, n = cars.size(); i < n; ++i ) { ((Car) cars.get(i)).bc.travelDist =0; ((Car) cars.get(i)).resetToCurve(); crashanims.clear(); } curveAnim = (key == 'G'); if (!anim) { myTime =0; isPaused = false; } } if (key=='3') { mode = (mode == d3mode) ? doNothingMode : d3mode; // camera(); } if ( key =='b' ) boxOnly = !boxOnly; if (key == 'f') firstPerson = !firstPerson; } if ( key == '+') velocityModifier *= 2; if (key == '-') velocityModifier /= 2; if (key == 'l') readFromFile(); if (key == 'w') writeToFile(); if ( key == 'i' ) saveFrame("img-####.tga"); if (key == 'c' ) showCars = !showCars; if (key == ' ') isPaused = !isPaused; if (key == 't' ) collisionTest = !collisionTest; if (key =='d') { for ( int i =0, n = cars.size(); i < n; ++i ) ((Car) cars.get(i)).detachFromCurve(myTime); } if ( mode == keyFrameMode && key=='s' ) { if ( curSelectedCar >= 0 ) { ((Car)cars.get(curSelectedCar)).addNewPos (); } } if ( mode == editDCMode && key=='e' ) { mode = doNothingMode; upleftDist = new pt (10,height*4/5); botrightDist = new pt (width-10,height); return; } if ( mode == doNothingMode && key=='e') { mode = editDCMode; upleftDist = new pt (10,0); botrightDist = new pt(width*4/5-10,height); return; } } void mousePressed() { if ( mode == d3mode) { // d3engine.mousePressed(); return; } if (mode == doNothingMode ) road.mousePressed (); if (createCarButton.pressed() && mode == doNothingMode) { Car car = new Car (cars.size()); pt dir = new pt (0,-40); pt p = new pt(height*4/5/2,width*7/8/2); car.poses.add ( new CarPose (p,dir )); car.updateBezier (true); cars.add (car); } if ( adjustCarButton.pressed ()) { if( mode == doNothingMode ) mode = keyFrameMode; else mode = doNothingMode ; } if(createCurveButton.pressed() && mode == doNothingMode ) { mode = createCurveMode; BezierCurve bc = new BezierCurve (); Car car = new Car (cars.size()); car.bc = bc; cars.add(car); curSelectedCar = cars.size()-1; return; } if ( mode == createCurveMode ) { anim = false; if ( mouseButton == LEFT && !keyPressed ) { pt c = new pt(0,0); c.setFromMouse (); limitTo (c, upleftCurve, botrightCurve, 0); BezierControlPoint bcp = new BezierControlPoint(c); BezierCurve b = ((Car) cars.get(cars.size()-1)).bc; b.addPoint (bcp); b.adjustLastDir (); } if (mouseButton == RIGHT || (keyPressed && key == CODED && keyCode == CONTROL && mouseButton == LEFT)) { constrainPt.setFromMouse(); } return; } if (adjustCurveButton.pressed() ) { if (mode == doNothingMode ) mode = adjustCurveMode; else mode = doNothingMode; } if ( mode == adjustCurveMode ) { anim = false; for ( int i =0, n = cars.size(); i < n; ++ i ) { BezierCurve cur = ((Car) cars.get(i)).bc; int sz = cur.pts.size(); if ( cur.handlePressEvent (false) ){ curAdjustCurve = i; curSelectedCar = i; if ( sz < cur.pts.size() ) ((Car) cars.get(i)).rebuildSpeedCurve (); break; } } } if ( mode == keyFrameMode ) { for ( int i =0, n = cars.size(); i < n; ++i ) { Car cur = (Car) cars.get(i); if ( cur.handlePressEvent() ) { curAdjustCurve = i; curSelectedCar = i; } } } if ( curSelectedCar >= 0 ) { DistanceCurve dc = ((Car) cars.get(curSelectedCar)).dc; dc.handlePressEvent (true); } } void mouseReleased () { if (mode == doNothingMode ) road.mouseReleased (); if (mode == adjustCurveMode && curAdjustCurve >= 0) { BezierCurve b = ((Car) cars.get(curAdjustCurve)).bc; if (b.handleReleaseEvent () ) { cars.remove(curAdjustCurve); curAdjustCurve = -1; curSelectedCar = -1; } } if ( mode == keyFrameMode && curAdjustCurve >= 0 ) { Car c = (Car) cars.get(curAdjustCurve); if ( c.handleReleaseEvent () ) { cars.remove( curAdjustCurve ); curAdjustCurve = -1; curSelectedCar = -1; } } if ( curSelectedCar >= 0 ) { DistanceCurve dc = ((Car) cars.get(curSelectedCar)).dc; if ( dc != null ) dc.handleReleaseEvent ( ); } curAdjustCurve = -1; } void mouseDragged() { if ( mode == d3mode) { // d3engine.mouseDragged(); return; } if ( mode == createCurveMode ) { if (mouseButton == LEFT && !keyPressed ) { BezierCurve b = ((Car) cars.get(cars.size()-1)).bc; if (b.pts.size() > 0) { b.getLastPoint().p.setFromMouse(); limitTo (b.getLastPoint().p, upleftCurve, botrightCurve,0); b.adjustLastDir (); } } if (mouseButton == RIGHT || (keyPressed && key == CODED && keyCode == CONTROL && mouseButton == LEFT) ) { BezierCurve b = ((Car) cars.get(cars.size()-1)).bc; BezierControlPoint bcp = b.getLastPoint(); pt cur = new pt(0,0); cur.setFromMouse(); cur.subPt (constrainPt); float change = cur.x + cur.y; if ( keyPressed == true && ( keyCode != CONTROL) ) { bcp.sleft = bcp.sright = bcp.sleft + change / 2; } else { float c = cos ( change / 180.0 * PI ); float s = sin ( change / 180.0 * PI ); pt dir = bcp.dir.makeCopy(); bcp.dir.x = c * dir.x - s * dir.y; bcp.dir.y = s * dir.x + c * dir.y; } constrainPt.setFromMouse (); } } if (mode == adjustCurveMode && curAdjustCurve >= 0 ) { BezierCurve b = ((Car) cars.get(curAdjustCurve)).bc; b.handleDragEvent( ); } if (mode == keyFrameMode && curAdjustCurve >= 0 ) { Car c = (Car) cars.get(curAdjustCurve); c.handleDragEvent( ); } if ( curSelectedCar >= 0 ) { DistanceCurve dc = ((Car) cars.get(curSelectedCar)).dc; if ( dc != null ) { dc.handleDragEvent ( ); } } } void update () { createCurveButton.update(); adjustCurveButton.update(); createCarButton.update(); adjustCarButton.update(); } void limitTo (pt p, pt upleft, pt bottomright, int dim ) { if ( dim <= 1) { if ( p.x < upleft.x ) p.x = upleft.x; if ( p.x > bottomright.x-1 ) p.x = bottomright.x-1; } if ( dim == 0 || dim == 2) { if (p.y < upleft.y ) p.y = upleft.y; if ( p.y > bottomright.y -1 ) p.y = bottomright.y-1; } } boolean isLimited (pt p, pt upleft, pt bottomright) { if ( (p.x < upleft.x) || (p.y < upleft.y ) || (p.x > bottomright.x-1 ) || ( p.y > bottomright.y -1 ) ) return false; else return true; } void mapPoint (pt p) { p.x = upleftDist.x + (botrightDist.x - upleftDist.x )*p.x; p.y = botrightDist.y - (botrightDist.y - upleftDist.y )*p.y; } void unmapPoint (pt p, int dim) { if ( dim <= 1 ) p.x = (p.x - upleftDist.x) / (botrightDist.x - upleftDist.x ); if ( dim == 0 || dim == 2) p.y = (p.y - botrightDist.y) / (-botrightDist.y + upleftDist.y ); } void readFromFile() { String[] strs = loadStrings("data.pts"); ArrayList a = new ArrayList(); for ( int i=0; i < Array.getLength(strs); ++i ) a.add ( strs[i] ); int n = Integer.parseInt ( (String) a.remove(0) ); for ( int i =0; i < n; ++i) { Car c = new Car(i); c.readFrom(a); cars.add(c); } road.readFrom(a); } void writeToFile() { ArrayList a = new ArrayList(); a.add ( "" + cars.size() ); for ( int i =0; i < cars.size(); ++i ) { ((Car) cars.get(i)).saveTo(a); } road.saveTo(a); String[] strs = new String[a.size() ]; for ( int i =0; i < a.size(); ++i ) strs[i] = (String) a.get(i); saveStrings ("data.pts", strs ); }