Willkommen auf unserem Seminar-Blog

Immer auf dem aktuellen Stand bleiben

Dieser Seminar-Blog befindet sich noch im Aufbau und wird in den kommenden Tagen entsprechend verfeinert.

Member Login

Lost your password?

Registration is closed

Sorry, you are not allowed to register by yourself on this site!

You must either be invited by one of our team member or request an invitation by email at viad.info {at} zhdk {dot} ch.

13. Game: Car Race

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();
  }
}