Helicopter Game (Sensor Display)

For my sensor display I wanted to make use of the proximity sensor. I chose to create a portrayal of an old flash game I remembered playing. I’m not sure what the origin of it is, but a portrayal of it can be found at http://www.helicopter-game.org/ . However, for my version the helicopter is controlled by the height of the player’s hand over the sensor device. The device is meant to look like a black box which is typically associated with aviation. I made sure to use similar colors for the game and the box.

Here is a video of the project running:

Here are some images:
helicopter_boxhelicopter_processing_display

Here is the fritzing diagram:
helicopter

Here is the Processing code:

// Helicopter Game
// If available this game will play using input from an arduino based accessory.
// Author: Matthew Kellogg
// Date: October 29, 2014
//Copyright 2014 Matthew Kellogg
// 
 
// Import the Serial library and create a Serial port handler
import processing.serial.*;
import ddf.minim.*;
Serial myPort;   

ArrayList ceilHeight = new ArrayList();
ArrayList floorHeight = new ArrayList();

float heliX = 200.0;
float heliY = 100.0;

color neonGreen = color(20, 200, 40);
int strokeW = 10;

int finalScore = 0;
boolean wrecked = false;

AudioPlayer player;
AudioPlayer explode;
Minim minim; //context
// Hey you! Use these variables to do something interesting. 
// If you captured them with analog sensors on the arduino, 
// They're probably in the range from 0 ... 1023:
int valueA;  // Sensor Value A
int valueB;  // Sensor Value B
 
//------------------------------------
void setup() {
  
  size(1280,800);
  
  // List my available serial ports
  int nPorts = Serial.list().length; 
  for (int i=0; i < nPorts; i++) {     println("Port " + i + ": " + Serial.list()[i]);   }      // Choose which serial port to fetch data from.    // IMPORTANT: This depends on your computer!!!   // Read the list of ports printed by the code above,   // and try choosing the one like /dev/cu.usbmodem1411   // On my laptop, I'm using port #4, but yours may differ.   if (Serial.list().length > 0){
  String portName = Serial.list()[0]; 
  myPort = new Serial(this, portName, 9600);
  serialChars = new ArrayList();
  }
  
  resetBounds();
  
  //audio
  minim = new Minim(this);
  player = minim.loadFile("helicopter-hovering-01.mp3", 2048);
  explode = minim.loadFile("explosion.mp3", 2048);
  player.loop();
}

void stop(){
  player.close();
  explode.close();
  minim.stop();
  super.stop();
}

void resetBounds(){
  ceilHeight.clear();
  floorHeight.clear();
  // ceiling and floor
  for (int i = 0; i -2 <= width/200; i++){
    ceilHeight.add(10);
    floorHeight.add(height - 10);
  }
}

void keyPressed(){
  if ((key == 'R' || key == 'r') && wrecked){
    wrecked = false;
    frameCount = 0;
    finalScore = 0;
    resetBounds();
    player.loop();
    explode.pause();
    explode.rewind();
  }
}

//------------------------------------
void draw() {
  background (10,20,60);
  
  if (wrecked){
    if ((frameCount/5)%2 == 0){
      fill(neonGreen);
      drawHelicopter(200, (int) heliY, false);
    }else{
      fill(255,0,0);
    }
    
    textAlign(CENTER);
    textSize(60);
    text("FINAL SCORE: " + finalScore,width/2, height/2-70);
    text("Press 'R' to restart", width/2, height/2 + 10);
  }else{
    // Process the serial data. This acquires freshest values. 
    if (myPort != null){
      processSerial();
      heliY = 0.9*heliY + 0.1*(map(valueA, 0, 100, height - 14*4, 100));
    }
    else{
      heliY = mouseY;
    }
    
    //Check bounds
    int checkIndex = (0 + 2*(frameCount%100))/100;
    int ceilBound = max((Integer)ceilHeight.get(checkIndex), (Integer)ceilHeight.get(checkIndex +1));
    int floorBound = min((Integer)floorHeight.get(checkIndex), (Integer)floorHeight.get(checkIndex + 1));
    if ((heliY - 100 < ceilBound) ||        (heliY + 60 > floorBound)){
      wrecked = true;
      finalScore = frameCount/5;
      player.pause();
      player.rewind();
      explode.play();
    }
    
    if (frameCount%100 == 0){
      ceilHeight.remove(0);
      floorHeight.remove(0);
      int pCeil = (Integer)ceilHeight.get(ceilHeight.size()-1);
      int pFloor = (Integer)floorHeight.get(floorHeight.size()-1);
      ceilHeight.add((int)random(max(10,pCeil-100), min(pCeil+100, pFloor -350)));
      floorHeight.add((int)random(max(pCeil +350, pFloor -100), min(height, pFloor + 100)));
    }
    
    drawBounds();
    drawHelicopter(200, (int)heliY,false);
      
    //score
    textAlign(RIGHT);
    textSize(30);
    String score = "Score: "+frameCount/5;
    int scoreW = (int)(textWidth(score));
    
    fill(0);
    strokeWeight(strokeW);
    stroke(neonGreen);
    rect(width - scoreW -20, -10, scoreW+30, 80);
    
    fill(neonGreen);
    noStroke();
    text(score, width - 10, 50);
  }
  
}

//draws the ceiling and floor
void drawBounds(){
  fill(0);
  strokeWeight(strokeW);
  stroke(neonGreen);
  beginShape();
  vertex(width+10, -20);
  vertex(-20,-20);
  println("Ceil size is " + ceilHeight.size());
  for (int i = 0; i< ceilHeight.size(); i++){
    vertex(200*i - 2*(frameCount%100), (Integer)ceilHeight.get(i));
  }
  endShape(CLOSE);
  
  beginShape();
  vertex(width+20, height+20);
  vertex(-20, height+20);
  for (int i = 0; i< floorHeight.size(); i++){     vertex(200*i - 2*(frameCount%100), (Integer)floorHeight.get(i));   }   endShape(CLOSE);   strokeWeight(1); } //bounds of the helicopter are -45,-25 to 30, 14 void drawHelicopter(int x, int y, boolean bounds){   pushMatrix();   fill(neonGreen);   noStroke();   translate(x,y);   scale(4, 4);   ellipse(0,-20, 60, 10);   ellipse(0, 0, 25, 16);   rect(-30, -4, 30, 6);   ellipse(-30,0, 15, 15);   if (bounds){     noFill();     rectMode(CORNERS);     rect(-45, -25, 30,14);     rectMode(CORNER);   }   strokeWeight(2);   stroke(neonGreen);   line(-8, 14, 8, 14);   line(8, 14, 12, 10);   popMatrix(); }   //--------------------------------------------------------------- // The processSerial() function acquires serial data byte-by-byte,  // as it is received, and when it is properly captured, modifies // the appropriate global variable.  // You won't have to change anything unless you want to add additional sensors.    /* The (expected) received serial data should look something like this:    A903  B412  A900  B409  A898  B406  A895  B404  A893  B404  ...etcetera.  */   ArrayList serialChars;      // Temporary storage for received serial data int whichValueToAccum = 0;  // Which piece of data am I currently collecting?  boolean bJustBuilt = false; // Did I just finish collecting a datum?   void processSerial() {     while (myPort.available () > 0) {
    char aChar = (char) myPort.read();
 
    // You'll need to add a block like one of these 
    // if you want to add a 3rd sensor:
    if (aChar == 'A') {
      bJustBuilt = false;
      whichValueToAccum = 0;
    } else if (aChar == 'B') {
      bJustBuilt = false;
      whichValueToAccum = 1;
    } else if (((aChar == 13) || (aChar == 10)) && (!bJustBuilt)) {
      // If we just received a return or newline character, build the number: 
      int accum = 0; 
      int nChars = serialChars.size(); 
      for (int i=0; i < nChars; i++) {          int n = (nChars - i) - 1;          int aDigit = ((Integer)(serialChars.get(i))).intValue();          accum += aDigit * (int)(pow(10, n));       }         // Set the global variable to the number we captured.       // You'll need to add another block like one of these        // if you want to add a 3rd sensor:       if (whichValueToAccum == 0) {         valueA = accum;         // println ("A = " + valueA);       } else if (whichValueToAccum == 1) {         valueB = accum;         // println ("B = " + valueB);       }         // Now clear the accumulator       serialChars.clear();       bJustBuilt = true;       } else if ((aChar >= 48) && (aChar <= 57)) {
      // If the char is between '0' and '9', save it.
      int aDigit = (int)(aChar - '0'); 
      serialChars.add(aDigit);
    }
  }
}

Here is the Arduino code:

/* 
 * Helicopter controller
 * Author: Matthew Kellogg
 * Date: October 22, 2014
 */
int ledPin = 5;    // LED connected to digital pin 9

void setup()  { 
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
} 

static const int lowThresh = 200;
static const int hiThresh = 612;

void loop()  {
  int val = analogRead(0);
  if (val > lowThresh && val < hiThresh){
    analogWrite(ledPin, map(val, lowThresh, hiThresh, 0, 255));
    //tone(11, map(val, lowThresh, hiThresh, 60, 4400));
    Serial.print("A" + String((int)map(val, lowThresh, hiThresh, 100, 0)) + "\n");
  } else { 
    analogWrite(ledPin, 0);
    //noTone(11);
  }
}

Comments are closed.