29. November 2011
Car Race
Gruppenarbeit: Dominik Stucky, Diego Martinez "Das OSC Protokoll (Open-Sound-Control) erlaubt es, auf eine einfache Art und Weise Daten über ein Netzwerk zu schicken". Dies haben wir gemeinsam in einer ersten kleinen Übung in der Klasse ausprobiert. Danach galt es eine sinnvolle Anwendung für dieses Protokoll zu finden. Wir haben uns für ein Game entschieden, bei dem vorerst mal zwei Personen jeweils ein Auto steuern. Als Steuerelement haben wir der Einfachheit halber Potentiometer verwendet und jeweils ein Arduino an einen Rechner angeschlossen. Mit OSC haben wird dann den analogen Input am zweiten Rechners zum Hauptrechner übermittelt. Die Oberfläche haben wir dann vollständig in Processing umgesetzt. Es gibt eine Kollisionsabfrage zwischen den beiden Autos, Fahrbahnrand, sowie zwischen Hindernissen und den Autos.#define POTI_PIN 0 void setup() { Serial.begin(9600); } void loop() { Serial.print(analogRead(POTI_PIN)); Serial.print(","); Serial.println(); }Processing: Senden und Empfangen von OSC-Daten
import processing.serial.*; import oscP5.*; import netP5.*; Serial myPort; OscP5 oscP5; NetAddress myRemoteLocation; int Val; void setup() { size(500, 500); background(0); myPort = new Serial(this, Serial.list()[0], 9600); oscP5 = new OscP5(this,12000); myRemoteLocation = new NetAddress("172.31.224.236",12000); } void draw() { println(Val); sendOSC(Val); } void serialEvent(Serial myPort) { if (myPort.available() > 0) { String completeString = myPort.readStringUntil(10); if (completeString != null) { trim(completeString); String seperateValues[] = split(completeString, ","); Val = int(seperateValues[0]); } } } void sendOSC(int theData) { OscMessage myMessage = new OscMessage("Diego"); myMessage.add(theData); oscP5.send(myMessage,myRemoteLocation); } void oscEvent(OscMessage theOscMessage) { print(theOscMessage.addrPattern()); print(theOscMessage.typetag());// i -= integer f = float println(theOscMessage.get(0).intValue()); }Game Code
import processing.serial.*; import processing.opengl.*; import ddf.minim.*; import oscP5.*; // OSC Libary import netP5.*; // net Library AudioPlayer song; AudioPlayer hitSound; OscP5 oscP5; // OSC Library NetAddress myRemoteLocation; // net Address import fullscreen.*; SoftFullScreen _fullScreen; Serial myPort; int inputPlayer1 = 1023/2; int inputPlayer2 = 1023/2; int boundryLeft = -100; int boundryRight = width+100; /*PVector[] vels = { new PVector(0, 0), new PVector(0, 0) };*/ float sunX, sunY, sunZ; float sunXdir=1, sunYdir=1, sunZdir=1; ArrayList street; int streetNum = 60; // C A R S Car[] cars = { new Car(0, 255, 102, true), new Car(51, 102, 255, true), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false), new Car(102, 102, 102, false) }; void setup() { noCursor(); // hide mouse cursor frameRate(36); smooth(); size(1240, 768, OPENGL); boundryLeft = -100; boundryRight = width+100; println(Serial.list()); // Prints the list of serial available devices (Arduino should be on top of the list) myPort = new Serial(this, Serial.list()[0], 9600); // Open a new port and connect with Arduino at 9600 baud oscP5 = new OscP5(this, 12000); // start oscP5, listening for incoming messages at port 12000 myRemoteLocation = new NetAddress("172.31.227.53", 12000); // The Address defined here is the Address of the Receiver street = new ArrayList(); for (int i=0; i<streetNum; i++) { Street strt = new Street(); strt.setStart(i, streetNum); street.add(strt); } Minim minim = new Minim(this); song = minim.loadFile("10 Fairyland.aif", 2048); song.setGain(-10.0); //song.loop(1); song.play(); for (int i=0; i<cars.length; i++) { cars[i].setHitSound(minim); } // FULLSCREEN _fullScreen = new SoftFullScreen(this); _fullScreen.enter(); } void draw() { // S E T U P sunX+=sunXdir*0.006; sunY+=sunYdir*0.003; //sunZ+=sunZdir*0.01; if (sunX>1.0) { sunXdir=-1; } else if (sunX<-1) { sunXdir=1; } if (sunY>1.0) { sunYdir=-1; } else if (sunY<-1) { sunYdir=1; } background((sunX+sunY)*40, (sunX+sunY)*60, (sunX+sunY)*40); // combine background color with sun coordinates directionalLight(255, 255, 225, sunX, sunY, -1); translate(0, 200, 100); rotateX(radians(-25)); // look down // SKY pushMatrix(); rotateX(radians(25)); translate(-(width*9/2), -3880, -6000); fill((sunX+sunY)*51, (sunX+sunY)*102, (sunX+sunY)*255); rect(0, 0, width*10, height*2); popMatrix(); //sendOSC(inputPlayer1); inputPlayer1 = int(width/2-(mouseX-width/2)); //inputPlayer2 = int(width/2-(mouseX-width/2)); // I N P U T P L A Y E R S int[] inputs = { inputPlayer1, inputPlayer2 }; float[] posPlayers = { 0, 0 }; // C A R S for (int i=0; i<cars.length; i++) { if (i<inputs.length) { float posPlayer = cars[i].draw(inputs[i], posPlayers); posPlayers[i] = posPlayer; } else { cars[i].draw(1023/2, posPlayers); } checkBoundaryCollision(cars[i]); } // S T R E E T for (int i=0; i<street.size(); i++) { Street strt = (Street) street.get(i); strt.draw(i, street.size()); } // C O L L I S I O N checkObjectCollision(cars); } void serialEvent(Serial myPort) // Is called everytime there is new data to read { if (myPort.available() > 0) { String completeString = myPort.readStringUntil(10); // Read the Serial port until there is a linefeed/carriage return if (completeString != null) // If there is valid data insode the String { String seperateValues[] = split(trim(completeString), "\t"); // Split the string everytime a delimiter is received inputPlayer1 = int(seperateValues[0]); } } } void sendOSC(int theData) { OscMessage myMessage = new OscMessage("Dominik"); myMessage.add(theData); oscP5.send(myMessage, myRemoteLocation); } void oscEvent(OscMessage theOscMessage) { //print(theOscMessage.addrPattern()); // name of the message //print(theOscMessage.typetag()); // what data type ('i'=integer, 'f'=float) inputPlayer2 = theOscMessage.get(0).intValue(); //println(theOscMessage.get(0).intValue()); // content of message } void checkObjectCollision(Car[] b) { // Abstände zwischen den Kreise PVector bVect = new PVector(); bVect.x = b[1].x - b[0].x; bVect.y = b[1].y - b[0].y; // Berechnung Betrag des Vektors float bVectMag = sqrt(bVect.x * bVect.x + bVect.y * bVect.y); //println(bVectMag); if (bVectMag < b[0].r + b[1].r) { if (b[0].x > b[1].x) { b[0].collisionLeft = true; b[1].collisionRight = true; } else { b[0].collisionRight = true; b[1].collisionLeft = true; } } else { b[0].collisionLeft = false; b[0].collisionRight = false; b[1].collisionLeft = false; b[1].collisionRight = false; } } void checkBoundaryCollision(Car ball) { if (ball.x > boundryRight) { ball.outRight = true; } else { ball.outRight = false; } if (ball.x < boundryLeft) { ball.outLeft = true; } else { ball.outLeft = false; } } void keyPressed() { switch(key) { case 'a': inputPlayer1-=20; break; case 's': inputPlayer1+=20; break; case 'd': inputPlayer2-=10; break; case 'f': inputPlayer2+=10; break; } }Klassen
import ddf.minim.*; class Car { float x, y, z, r, m; float boxWidthOrig=100, boxHeightOrig=50, boxLengthOrig=200; float boxWidth, boxHeight, boxLength; float playerX; int cR,cG,cB, cRcollision, cGcollision, cBcollision; boolean outLeft = false; boolean outRight = false; boolean collisionLeft = false; boolean collisionRight = false; boolean player = true; boolean isHit = false; int speedSide = 40; int hitRotX = 0, hitRotY = 0, hitRotZ = 0; float hitRotXinc, hitRotYinc, hitRotZinc; int hitBoxLength = 50; AudioPlayer hitSound; Car(int icR, int icG, int icB, boolean iplayer) { cR=icR; cG=icG; cB=icB; cRcollision=icR+102; cGcollision=icG+102; cBcollision=icB+102; player = iplayer; z = -(this.boxLength/2); reset(); } void setHitSound(Minim minim) { this.hitSound = minim.loadFile("hit.aiff", 2048); this.hitSound.rewind(); this.hitSound.play(); } void reset() { this.isHit=false; this.hitRotX = 0; this.hitRotXinc = random(2,10); this.hitRotYinc = random(2,10); this.hitRotZinc = random(2,10); this.boxWidth=this.boxWidthOrig; this.boxHeight=this.boxHeightOrig; this.boxLength=this.boxLengthOrig; if (player==false) { this.boxLength = this.boxWidth; this.boxHeight = this.boxWidth; } } float draw(int inputPlayer, float[] posPlayers) { r = map(abs(map(inputPlayer,0,1023,-1,1)), 0, 1, this.boxWidth/2, this.boxLength/2); pushMatrix(); pushStyle(); noStroke(); if (this.collisionLeft==true || this.collisionRight==true) { fill(cRcollision, cGcollision, cBcollision); } else if (isHit==true) { fill(255); } else { fill(cR,cG,cB); } if (outRight==true || collisionRight==true) { this.playerX-= speedSide; } else if (outLeft==true || collisionLeft==true) { this.playerX+= speedSide; } else { this.playerX+= map(inputPlayer,0,1023,-speedSide,speedSide); } if (player==false) { // O B S T A C L E if (z>800 || y<-400) { // set back to beginning (loop) z = random(-6000,-3000); x = random(0, width); y = height/2; reset(); } // animate if hit if (this.isHit == true) { // change length, move up and forward y-= 40; z-=150; this.boxLength=this.hitBoxLength; } else { y = height/2; } z +=50; // movement forward } else { y = height/2; x = (width/2)+this.playerX; } // when to check for collision if (z>this.boxLength*-2 && z<this.boxLength*-1) { //println("CROSSING LINE: "+ x); for(int i=0; i<posPlayers.length; i++) { if (abs(x-posPlayers[i])<this.boxWidth) { //println("HIT BY CAR "+i); this.isHit = true; if ( !this.hitSound.isPlaying() ) { this.hitSound.rewind(); this.hitSound.play(); } } } } translate(x, y, z); rotateY(radians(map(inputPlayer,0,1023,60,-60))); pushMatrix(); if (this.isHit==true) { // rotate object if hit this.hitRotX+=this.hitRotXinc; this.hitRotY+=this.hitRotYinc; this.hitRotZ+=this.hitRotZinc; rotateX(radians(this.hitRotX)); rotateX(radians(this.hitRotY)); rotateZ(radians(this.hitRotZ)); } else { // light movement along z-axis (left, right) rotateZ(radians(map(inputPlayer,0,1023,-30,30))); } // body car box(this.boxWidth,this.boxHeight,this.boxLength); if (player==true) { // roof car pushMatrix(); translate(0, -1*this.boxHeight/1.35, 25); box(this.boxWidth-10,this.boxHeight/2,this.boxLength/2); popMatrix(); } popMatrix(); if (player==true) { // shadow car pushMatrix(); translate(-1*(this.boxWidth/2), this.boxHeight/2+20, -1*(this.boxLength/2)); rotateX(radians(90)); fill(0); rect(0,0,this.boxWidth,this.boxLength); popMatrix(); popStyle(); } popMatrix(); //println(this.outLeft+" :: "+this.outRight); return x; } }
class Street { int roadMov = 0; int roadSpeed = 50; int sWidth = 200; float sLength; int sGap = 0; float cR; float cG; float cB; int lineWidth = 15; Street() { float tmp = random(130,160); cR = tmp+10; cG = tmp; cB = tmp; sLength = width*1.2; } void setStart(int index, int total) { this.roadMov = 600 - (index*(sWidth+sGap)); } void draw(int index, int total) { this.roadMov+= roadSpeed; if (this.roadMov>600) { this.roadMov = 600 - ((total)*(sWidth+sGap)) + sWidth/2; } pushMatrix(); translate((width-sLength)/2,height/2+50,this.roadMov); rotateX(radians(-90)); pushStyle(); noStroke(); fill(cR,cG,cB); rect(0,0,sLength,sWidth); pushMatrix(); translate(-1.0*sWidth,0,sWidth/2); box(sWidth,sWidth,sWidth); popMatrix(); pushMatrix(); translate(sLength+sWidth,sWidth,sWidth/2); box(sWidth,sWidth,sWidth); popMatrix(); if (index%2==0) { // LINES pushMatrix(); translate((sLength-lineWidth)/6*1,0,-5); fill(224); rect(0,0,lineWidth,sWidth); popMatrix(); pushMatrix(); translate((sLength-lineWidth)/6*2,0,-5); fill(224); rect(0,0,lineWidth,sWidth); popMatrix(); pushMatrix(); translate((sLength-lineWidth)/6*3,0,-5); fill(224); rect(0,0,lineWidth,sWidth); popMatrix(); pushMatrix(); translate((sLength-lineWidth)/6*4,0,-5); fill(224); rect(0,0,lineWidth,sWidth); popMatrix(); pushMatrix(); translate((sLength-lineWidth)/6*5,0,-5); fill(224); rect(0,0,lineWidth,sWidth); popMatrix(); } // side knobs pushMatrix(); translate(-1.0*sWidth,0,sWidth/2-112); fill(255); box(sWidth/2,24,24); popMatrix(); pushMatrix(); translate(sLength+sWidth,sWidth,sWidth/2-112); fill(255); box(sWidth/2,24,24); popMatrix(); popStyle(); popMatrix(); } }