Antonius: Final Project: Ghost Hunter

Final Project: Ghost Hunter

Date: May 18th

Instructor: Antonius

Aim:  Make a project that incorporate processing and Arduino in it.

Material: Processing, Arduino, Arduino kit, conductive tape, sponge, sponge mat, toy sword, accelerometer, wires.

Process:

  1. Designing: As I mentioned in my final project essay, I planned to make an interactive game. The user can control the moving of the character in the game by stepping on different part on the mat. The user can also kill enemies in the game by swing the actual sword. Initially I also designed a shield that the user can activate to block the attack from the enemies, but due to time limit and it might be too complicate for the plays to control so many controllers, I abandoned this part.
  2. Making the game:

I started by making the game in Processing first. Instead of using actual physical input, I use keyboard input first when building the game. The game is consisted of two components, the player and the enemies. I used the function keyPressed to control the character to move in four direction, by pressing the four keys “w”, “a”, “s”, “d”.

When making the enemies, at first I created them to let them chase the character. One problem with it is that all the enemies would overlap with each other after following the character for some time. To deal with this problem I tried several approaches, like detecting the distance between each enemy, but failed. In the end, I decided to let the enemies run randomly and let the character to catch them.

The enemies were made using object in processing. I defined all the characteristics for the enemies in a separate class, including color, position, speed, behavior after running into the character, etc. Then I use array list to call the enemies. In that case, each enemy could behave on their own, and when they are supposed to be killed, I could simply remove them from the list.

  1. Creating the input structure

As I mentioned in my design, I planned to let users to use their body movements to control the action of the character. The moving of the character was designed to be controlled by stepping on a stepping board on the ground. To control the character to move un, down, left and right, the players have to step on the front, back, left, right panels on the board. Originally I decided to use force sensor to be the information input, but considering that stepping might cause breaking the force sensor, I changed my mind to use soft button as input. With the help from professor Antonius, I was able to make my own soft button. Two conductive materials slicked on two separated boards, a sponge with a hole in it was used to connect the two boards. In this way, when stepping on the board, the conductive materials will get connected from the hole in the sponge, forming a whole loop that conducts current, which used to send input information to Arduino.

IMG_1599

The next step is to control the attack effect of the character. I used the accelerometer as input. When the user is swing the sword, the change in acceleration will be sensed and send to processing to trigger an “attack zone” around the character. And when the enemies overlapping with the “attack zone”, they will be eliminated.

IMG_1634

  1. Improving gaming experience

To make my game more playable, I add a time limit to the game. If the player can kill all the enemies in the limiting time, a screen showing “you win” will pop out; and if the enemies are not all killed in the time limit, a screen showing “game over” will pop out. What’s more to make the game more responsive, I also added sound effect when the enemies bounced against the character, and a sword swing effect when the user is swing the sword.

The pictures and actual effects are shown below.

IMG_1633

IMG_1635

IMG_1639

IMG_1637

//This is the processing code
import processing.serial.*;
Serial myPort;
int valA, valB, valC, valD;

ArrayList<Car> cars;
int x, y;
int x1, y1, a1, b1;


void setup() {
  myPort = new Serial(this, Serial.list()[2], 9600);
  size(720, 540);
  x = width/2;
  y = height/2;
  rectMode(CENTER);

  cars = new ArrayList<Car>();
  for (int i = 0; i < 10; i++) {
    cars.add(new Car(color(255, 0, 0), random(0, width), random(0, height), 2, 1));
  }
}

void draw() { 
  while(myPort.available() > 0){
     valA = myPort.read();
     valB = myPort.read();
     valC = myPort.read();
     valD = myPort.read();
  }
  background(100);
  //rect(x1, y1, a1, b1);
  fill(255);
  ellipse(x, y, 50, 50);
  
  if (valA > 100) {
    x = x - 3;
    x1 = x - 20;
    y1 = y;
   // a1 = 80;
   //b1 = 50;
  }
  if (valB > 100) {
    y = y - 3;
    x1 = x;
    y1 = y - 20;
    //a1 = 50;
    //b1 = 80;
  } 
  if (valC > 100) {
    x = x + 3;
    x1 = x + 20;
    y1 = y;
    //a1 = 80;
    //b1 = 50;
  } 
  if (valD > 100) {
    y = y + 3;
    x1 = x;
    y1 = y + 20;
    //a1 = 50;
    //b1 = 80;
  }
    
  if (y < 25){
    y = y + 3;
  }
  if (y > height - 25){
    y = y - 3;
  }
  if (x < 25){
    x = x + 3;
  }
  if (x > width - 25){
    x = x - 3;
  }
    

  for (int i = 0; i < cars.size(); i++) {
    Car car = cars.get(i);
    car.drive();
    car.display();
    if (dist(car.xpos, car.ypos, x, y) < 35) {
      cars.remove(i);
    }
  }
}


class Car { 
  color c;
  float xpos;
  float ypos;
  float xspeed;
  float yspeed;


  // The Constructor is defined with arguments.
  Car(color tempC, float tempXpos, float tempYpos, float tempXspeed, float tempYspeed) { 
    c = tempC;
    xpos = tempXpos;
    ypos = tempYpos;
    xspeed = tempXspeed;
    yspeed = tempYspeed;
  }

  void display() {
    stroke(0);
    fill(c);
    ellipse(xpos, ypos, 20, 20);
  }

  void drive() {
    xpos = xpos + xspeed;
    if (xpos > width) {
      xspeed = -xspeed;
    } else if (xpos < 0) {
      xspeed = -xspeed;
    }
    ypos = ypos + yspeed;
    if (ypos > height) {
      yspeed = -yspeed;
    } else if (ypos < 0) {
      yspeed = -yspeed;
    }
  }
}


//This is the Arduino code
int valA, valB, valC, valD, valE;

#include <Wire.h>
#include <ADXL345.h>


ADXL345 adxl;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  adxl.powerOn();

  //set activity/ inactivity thresholds (0-255)
  adxl.setActivityThreshold(75); //62.5mg per increment
  adxl.setInactivityThreshold(75); //62.5mg per increment
  adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?
 
  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(1);
 
  //look of inactivity movement on this axes - 1 == on; 0 == off
  adxl.setInactivityX(1);
  adxl.setInactivityY(1);
  adxl.setInactivityZ(1);
 
  //look of tap movement on this axes - 1 == on; 0 == off
  adxl.setTapDetectionOnX(0);
  adxl.setTapDetectionOnY(0);
  adxl.setTapDetectionOnZ(1);
 
  //set values for what is a tap, and what is a double tap (0-255)
  adxl.setTapThreshold(50); //62.5mg per increment
  adxl.setTapDuration(15); //625us per increment
  adxl.setDoubleTapLatency(80); //1.25ms per increment
  adxl.setDoubleTapWindow(200); //1.25ms per increment
 
  //set values for what is considered freefall (0-255)
  adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment
 
  //setting all interrupts to take place on int pin 1
  //I had issues with int pin 2, was unable to reset it
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );
 
  //register interrupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
}

void loop() {
  // put your main code here, to run repeatedly:
  //Serial.println(analogRead(0));
int x,y,z;  
  adxl.readXYZ(&x, &y, &z); //read the accelerometer values and store them in variables  x,y,z
  double xyz[3];
  double ax,ay,az;
  adxl.getAcceleration(xyz);
  ax = xyz[0];
  ay = xyz[1];
  az = xyz[2];
  
  
  if (ax < -1.2 || ax > 1.2 || ay < -1.2 || ay > 1.2 || az < -1.2 || az > 1.2){
    valE = 1;
  }
  else{
    valE = 0;
  }
  
  
  valA = map(analogRead(0), 0, 1023, 0, 255);
  valB = map(analogRead(1), 0, 1023, 0, 255);
  valC = map(analogRead(2), 0, 1023, 0, 255);
  valD = map(analogRead(3), 0, 1023, 0, 255);
  Serial.write(valA);
  //delay(10);
  Serial.write(valB);
  //delay(10);
  Serial.write(valC);
  //delay(10);
  Serial.write(valD);
  Serial.write(valE);
  delay(30);
  
  
}

Leave a Reply