Final Project Progress – Ngoc and Maaz

This week, we were supposed to start working on the final project right after finalizing our proposals. The link to the proposal for the game Ngoc and I are working on can be found below.

[Week 12] Final project proposal – Ngoc and Maaz

Update: Wednesday 14th April – Sunday 18th April

Ngoc and I sat down and discussed the Processing part of the game. Based on our past experience of working on games, we had slightly different opinions on how to go about the classes our game would contain, but there’s a lot I can learn from a sophomore and I believed that her idea of creating 4 different classes would make it easier for us to work on different parts of the game. The 4 classes and a description of what all of them would do are as follows:

  • Item

The Item Class will consist of all attributes of items which are to fall down the screen. These attributes will include the initial x and y coordinates of the items, their velocities as they fall down the screen, radii, image (to be displayed for each item) and more. The Item Class will also consist of relevant methods for all items, including their update() and display() methods.

  • Player

The Player class will characterize the user of the Processing program. The most fundamental attribute of a Player object is the x coordinate which is communicated from the Arduino program and updated accordingly. It will also have a display() method to show where the player is on the screen (represented by a sprite). Other information will also be communicated between different classes like Player, Level, Game to determine when the player will appear on the screen etc.

  • Level

A Level object encompasses one full game level and includes a number of objects from other classes, for example one level will include one player and multiple items, as well as new entities like performance metrics. This class coordinates the interactions between Item class and Player class like checking for collisions, and supports other key game functionalities like updating and displaying performances.

  • Game

An instance of the Game class will represent one entire game which will have four levels, each corresponding to one of the four academic years. It will also contain its own update() and display() functions, which will coordinate certain conditions and outputs to deal with those conditions. Moreover, it will also be responsible for calling the update() functions of other objects which are instantiated within the Game class and the Level class.

Remote Control Testing

The part we expect to be the hardest is getting the remote control to work. From working on previous assignments, we have seen that the distance measuring sensor gives pretty unstable readings and we were concerned with how that might reflect in our program, since smooth and correct mapping of the movement of the remote control onto the screen is a key game function.

We first experimented with mapping the distance onto the movement of a circle on a blank screen to make sure that we could get the sensor to work as we want. As expected, the movement of the circle was quite jittery and glitchy, but it did move in the way we intended. So this proved that we could indeed move the whole Arduino and breadboard combination as a remote control for the game.

We then experimented further with the Processing code to smoothen the movement of the player (which is still represented by a single moving circle for the sake of simplicity). We went back to an earlier example and used it in our Processing code, which gave much smoother player movement.

The differences between no smoothing vs. with smoothing are recorded as can be seen in the short demo:

The Arduino and Processing code for testing the remote control is as following:

GitHub link: https://github.com/nhungoc1508/not-so-creative-final-project/tree/master/remote-control

Arduino code:

const int trigPin = 11;
const int echoPin = 12;

float distance;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("0");
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
//  distance = getDistance();
//  Serial.println(distance);
  while (Serial.available()) {
    if (Serial.read() == '\n') {
      distance = getDistance();
      delay(1);
      Serial.println(distance);
    }
  }
}

float getDistance()
{
  float echoTime;                   //variable to store the time it takes for a ping to bounce off an object
  float calculatedDistance;         //variable to store the distance calculated from the echo time

  //send out an ultrasonic pulse that's 10ms long
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  echoTime = pulseIn(echoPin, HIGH);      //use the pulsein command to see how long it takes for the
                                          //pulse to bounce back to the sensor

  // calculatedDistance = echoTime / 148.0;  //calculate the distance of the object that reflected the pulse (half the bounce time multiplied by the speed of sound)
  calculatedDistance = echoTime / 58.0;

  return calculatedDistance;              //send back the distance that was calculated
}

Processing code:

import processing.serial.*;
Serial myPort;
float xPos=0;
float yPos;
float smoothedNum = 0;
float prevX=0;

void setup() {
  //size(960, 720);
  fullScreen();
  yPos=height/2;
  //printArray(Serial.list());
  String portname=Serial.list()[4]; //[4] "/dev/cu.usbmodem1101"
  //println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');
}

void draw() {
  background(255);
  fill(100, 200, 200);
  noStroke();
  if (abs(xPos-smoothedNum) < width*.3) {
    smoothedNum += (xPos-smoothedNum)*.2;
  }
  ellipse(smoothedNum, yPos, 50, 50);
  prevX = smoothedNum;
}

void serialEvent(Serial myPort) {
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null) {
    println(s);
    int value = int(s);
    println(value);
    xPos=(float)map(value, 0, 50, 0, width);
  }
  myPort.write("\n");
}

 

Extra Credit – Arduino + Processing Game

For the Week 3 assignment, I made a game. This game was NYUAD-themed and the player used arrow keys to make Faiza the falcon avoid certain obstacles and get a 4.0 GPA. The link to that post is attached below.

Week 3 – Go, get that 4.0!

This extra credit assignment is an extension of my Week 3 assignment, except that it makes use of buttons instead of arrow keys. There are 4 different buttons, each corresponding to a single direction.

I figured that the purpose of this assignment was to understand serial communication well, so I tried making good use of a game I had already made earlier.

The group exercises which were due on Monday, together with working on this game, have allowed me to understand the communication between Processing and Arduino a lot better.

Arduino code:

const int yellowButtonPin = 2;
const int greenButtonPin = 4;
const int redButtonPin = 7;
const int blueButtonPin = 8;


void setup() {
  Serial.begin(9600);
  Serial.println("0");
  pinMode(yellowButtonPin, INPUT);
  pinMode(greenButtonPin, INPUT);
  pinMode(redButtonPin, INPUT);
  pinMode(blueButtonPin, INPUT);
}

void loop() {
  while (Serial.available()) {
    if (Serial.read() == '\n') {
      int yellow_button = digitalRead(2);
      delay(1);
      int green_button = digitalRead(4);
      delay(1);
      int red_button = digitalRead(7);
      delay(1);
      int blue_button = digitalRead(8);
      delay(1);

      Serial.print(yellow_button);
      Serial.print(",");
      Serial.print(green_button);
      Serial.print(",");
      Serial.print(red_button);
      Serial.print(",");
      Serial.println(blue_button);
    }
  }

}

Processing code:

import java.lang.Math;
import processing.sound.*;
import processing.serial.*;
Serial myPort;
SoundFile file;

String audioName = "intro.mp3";
String path;

PImage[] images;
Game game;

// creating an array for distractions which are used later
Distractions[] distractions;

class Faiza{
  float posX, posY;
  float radius;
  float velocityX;
  float velocityY;
  float imgwidth, imgheight;
  String directionX;
  //String keyY, keyX;
  boolean move_up, move_down, move_right, move_left;
  boolean alive;
  int counter, frame;
  
  Faiza(float x, float y, float r, float img_w, float img_h){
    posX = x;
    posY = y;
    radius = r;
    velocityX = 0;
    velocityY = 0;
    imgwidth = img_w;
    imgheight = img_h;
    directionX = "right";
    move_up = false;
    move_down = false;
    move_right = false;
    move_left = false;
    alive = true;
    counter = 0;
    frame = 0;
  }
  
  void display(){
    update();
    if (directionX == "right"){
      image(images[0], float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int(frame * imgwidth), 0, int((frame + 1) * imgwidth), int(imgheight));
    }
    else if (directionX == "left"){
      image(images[0], float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int((frame + 1) * imgwidth), 0, int(frame * imgwidth), int(imgheight));
    }
  }
  
  void update(){
    //The condition below is for when Faiza moves left
    if (move_left == true){
       velocityX = -2;
       directionX = "left";
       if (posX - radius + velocityX < 6){
         velocityX = 0;
       }
       posX += velocityX;
    }
                    
    //The condition below is for when Faiza moves right
    else if (move_right == true){
      velocityX = 2;
      directionX = "right";
      if (posX + radius + velocityX > 1018){
        velocityX = 0;
      }
      posX += velocityX;
    }

    //If none of the left and right keys are being pressed, Faiza stops moving horizontally
    else{
      velocityX = 0;   
    }        
    
    if (move_up == true){
      velocityY = -2;
      if (posY - radius + velocityY <= 5){
        velocityY = 0;
      }
      posY += velocityY;
    }
                    
//The condition below is for when Faiza moves downwards
    else if (move_down == true){
      velocityY = 2;
      if (posY + radius + velocityY >= 762){
        velocityY = 0;
      }      
      posY += velocityY;
    }
                    
//If none of the up and down keys are being pressed, Faiza stops moving vertically
    else{
    velocityY = 0;
    }
  
    if (distance(game.gpa) <= (radius + game.gpa.radius)){
      game.level += 1;
    }
    
    if (!(posX >= 0 && posX <= 100 && posY >= 530 && posY <= 640)){ 
      for (int i = 0; i < 6; i++){
        if (distance(distractions[i]) <= radius + distractions[i].radius){
          counter += 1;
          println(counter);
          alive = false;
        }
      }
    }
  }
  
  // this distance method will be used to check for collisions with distractions
  double distance(Distractions target){
    float a = (posX - target.posX);
    float b = (posY - target.posY);
    double c = Math.pow(a, 2);
    double d = Math.pow(b, 2);
    return Math.pow(c + d, 0.5);
  }
  
   // this distance method will be used to check for collisions with the gpa (marking the end of the game)
   double distance(GPA target){
    float a = (posX - target.posX);
    float b = (posY - target.posY);
    double c = Math.pow(a, 2);
    double d = Math.pow(b, 2);
    return Math.pow(c + d, 0.5);
  }
}

class Distractions{
  float posX, posY;
  float radius;
  float imgwidth, imgheight;
  int frame;
  PImage img;
  float velocityX, velocityY;
  
  Distractions(float x, float y, float r, String _img, float img_w, float img_h){
    posX = x;
    posY = y;
    radius = r;
    img = loadImage(_img);
    imgwidth = img_w;
    imgheight = img_h;
    frame = 0;
    velocityX = random(2,5);
    velocityY = -1 * random(2,5);
  }
  
  void update(){
    if (posX + radius >= 1024){
      velocityX *= -1;
    }
    if (posX - radius <= 0){
      velocityX *= - 1;
    }
    if (posY - radius <= 10){
      velocityY *= -1;
    }
    if (posY + radius >= 780){
      velocityY *= -1;
    }
    
    posX += velocityX;
    posY += velocityY;
  }
  
  void display(){
    update();
    image(img, float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int(frame * imgwidth), 0, int((frame + 1) * imgwidth), int(imgheight));
  }
}

class GPA{
  float posX, posY;
  float radius;
  float imgwidth, imgheight;
  int frame;
  
  GPA(float x, float y, float r, float img_w, float img_h){
    posX = x;
    posY = y;
    radius = r;
    imgwidth = img_w;
    imgheight = img_h;
    frame = 0;
  }
  
  void display(){
    image(images[1], float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int(frame * imgwidth), 0, int((frame + 1) * imgwidth), int(imgheight));
  }
}

class Game{
  float game_width, game_height;
  Faiza faiza;
  GPA gpa;
  int level;
  
  Game(float game_wth, float game_hght){
    level = 1;
    game_width = game_wth;
    game_height = game_hght;
    faiza = new Faiza(34, 585, 27, 66, 66);
    gpa = new GPA(990, 35, 25, 70, 56);
  }
  
  void update(){
    if (faiza.alive == false){
      faiza.posX = 34;
      faiza.posY = 585;
      faiza.alive = true;
    }
  }
  
  void display(){
    update();
    
    image(images[2], 0, 0);
    
    if (level == 1){
      textMode(CENTER);
      textSize(40);
      fill(255, 213, 43);
      text("GET THAT 4.0!", 310, 65);
    }
    
    if (level != 1){
      textSize(150);
      fill(255, 213, 43);
      text("GAME", 270, 220); 
      text("OVER", 290,350);
      textSize(50);
      text(faiza.counter + " distractions later,", 240, 550);
      text("you achieved that 4.0 GPA!", 200, 600);
    }
    
    if (level == 1){
      faiza.display();
      gpa.display();
    }
    
    for (int i = 0; i < 6; i++){
      distractions[i].display();
    }
    
  }
}
  

void setup(){
 size(1024,768);
 
 printArray(Serial.list());
 String portname=Serial.list()[1];
 println(portname);
 myPort = new Serial(this,portname,9600);
 myPort.clear();
 myPort.bufferUntil('\n');
 
 game = new Game(1024, 768);
 path = sketchPath(audioName);
 file = new SoundFile(this, path);
 file.loop();
 images = new PImage[3];
 images[0] = loadImage("faiza.png");
 images[1] = loadImage("gpa.png");
 images[2] = loadImage("background.png");
 
 distractions = new Distractions[6];
 distractions[0] =  new Distractions(100, 300, 58, "jake.png", 120, 120);
 distractions[1] =  new Distractions(444, 333, 48, "insta.png", 100, 100);
 distractions[2] =  new Distractions(900, 120, 48, "facebook.png", 100, 100);
 distractions[3] =  new Distractions(887, 635, 48, "netflix.png", 100, 100);
 distractions[4] =  new Distractions(134, 587, 48, "youtube.png", 100, 100);
 distractions[5] =  new Distractions(55, 100, 48, "ps.png", 120, 120);
}

void draw(){
  background(255, 255, 255);
  game.display();
}

// allowing key presses to dictate Faiza's movement
void keyPressed(){
  if (key == CODED){
    if (keyCode == RIGHT){
      game.faiza.move_right = true;
    }
    if (keyCode == LEFT){
      game.faiza.move_left = true;
    }
    if (keyCode == UP){
      game.faiza.move_up = true;
    }
    if (keyCode == DOWN){
      game.faiza.move_down = true;
    }
  }
}
    
    
void keyReleased(){
  if (key == CODED){
    if (keyCode == RIGHT){
      game.faiza.move_right = false;
    }
    if (keyCode == LEFT){
      game.faiza.move_left = false;
    }
    if (keyCode == UP){
      game.faiza.move_up = false;
    }
    if (keyCode == DOWN){
      game.faiza.move_down = false;
    }
  }
}


void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    println(s);
    int values[] = int(split(s,','));
    
    if (values.length == 4){
      if (values[0] == 1){
        game.faiza.move_left = true;
      }
      else{
        game.faiza.move_left = false;
      }
      
      if (values[1] == 1){
        game.faiza.move_down = true;
      }
      else{
        game.faiza.move_down = false;
      }
      
      if (values[2] == 1){
        game.faiza.move_up = true;
      }
      else{
        game.faiza.move_up = false;
      }
      
      if (values[3] == 1){
        game.faiza.move_right = true;
      }
      else{
        game.faiza.move_left = false;
      }
    }
  }
  
  myPort.write("\n");
  
}

 

Final Project Proposal

For my final project, I’m going to build something for this Zoom era. I get a lot of migraines and sometimes just need to put my head down during classes/meetings…but, I don’t want to fall asleep!

This contraption aims to detect when the user has put their head down and gently remind them to stay present. The user also will have the option to display the text of what is being said.

The Arduino program:

Input: when has the user put their head down. I will use either an ultrasonic sensor or use this Capacitor Sensor library to create a sensor using foil inside the pillow.

Output: gentle sound using piezo buzzer depending on input in Processing program, also sends signal to Processing program that user has put head down

(I would also like to explore creating vibrations as output but am not sure how to do this)

 

The Processing program (p5.js):

Input: signal from Arduino that user has put head down,  speech of class/meeting, time interval user wants to be reminded at

Output: display text of class/meeting, sends signal to Arduino of when to create sound/vibrations

 

Considerations:

The p5 program will have an alert: the user should only display the transcript if there is consent from the other participants in the Zoom call (ex: meeting is being recorded). The program will also not save the text anywhere and will be cleared from the screen after a certain time.

The P5 speech library I wanted to use (Thanks Aaron for the rec!) seems to be better than expected at recognizing names that aren’t typically used in English (it recognized a lot of my friends’ names and mine when I experimented), but it will definitely not be perfect, so I’m not sure whether to proceed with the name recognition alarm feature.

Arduino + Processing Game [EXTRA CREDIT]

Project Outline

So for this project, we will be using an Arduino Uno Board and an SR-04 Ultrasonic sensor, a breadboard, and a few wires. So this game is built upon the midterm game that I have created previously, Drowning Diver. But this time around, the game is controlled with an ultrasonic sensor that feels the distance between whatever is put in front of it. When sensor is covered it goes up, when user puts his fingers away that cover sensor the diver goes down and drowns))

To be honest, I really wanted to make a game using screen. Last lesson when we were having a group discussion of our ideas, Alima has mentioned that we have a so-called screen that can display on it. That was the time when I got so excited to working with it, but immediately that idea backfired.

PROCESSING CODE

PImage wall;
PImage character;

import processing.serial.*;
int DistanceUltra;
int IncomingDistance;
Serial myPort;
String DataIn;
Pipe p1 = new Pipe();
Pipe p2 = new Pipe();
Pipe p3 = new Pipe();
 
//bird height and width location
float birdy = 46;
float birdx = 56;
float gravity = 5;
//float jumpForce = 15;
 
//the speed of the pipes
int speed;
 
//score and game state
boolean gameOver = false;
int score = 0;
int highscore = 0;
 
int point = 1;
 
color birdColor = color(255, 204, 0);
 
 
void setup(){
  size(800,400);
  wall=loadImage("underwater.png");
  character=loadImage("scuba.png");
  p1.x = width + 80;
  p2.x = width + 200;
  p3.x = width + 400;
  printArray(Serial.list());
  String portname=Serial.list()[2];
  println(portname);
  myPort = new Serial(this,portname,9600);
  myPort.bufferUntil(10);
}
void serialEvent (Serial myPort){
DataIn = myPort.readString();
println(DataIn);
IncomingDistance = int(trim(DataIn));
println("incoming distance="+IncomingDistance);
if (IncomingDistance>1 && IncomingDistance<100 ) { DistanceUltra = IncomingDistance; //save the value only if its in the range 1 to 100 } }
}
}
 
void draw(){
 
  background(wall);
  p1.pipe();
  p2.pipe();
  p3.pipe();
 
  fill(birdColor);
  ellipse(birdx, birdy, 55,55);
 // birdy += gravity;
  play();
  success(p1);
  success(p2);
  success(p3);
 
  if (IncomingDistance>10)
  {
    //birdy -= jumpForce;
    birdy -= gravity;
  }    
  else
  {
    birdy += gravity;
  }
  
}
 
 
void play(){
 
  if(gameOver == false)
  {
    speed = 2;
    p1.x -= speed;
    p2.x -= speed;
    p3.x -= speed;
   
    textSize(24);
    fill(255,255,255);
    text(score, width/2, 30);  
  }
 
  if(gameOver == true)
  {
    speed = 0;
    p1.x -= speed;
    p2.x -= speed;
    p3.x -= speed;
   
    if( highscore < score)
    {
       highscore = score;
    }
   
    textSize(16);
    fill(0, 102, 153);
    textAlign(CENTER);
    text("Click : Play Again", width/2, height/2);
    text("Score: " + score, width/2, height/2 - 20);
    text("High-Score: " + highscore, width/2, height/2 - 40);
   
    if (mousePressed)
    {
       delay(900);
       score = 0;
       gameOver = false;
       birdy = 100;
       birdx = 56;
       p1.x = width + 50;
       p2.x = width + 220;
       p3.x = width + 370;
       p1.top = random(height/2);
       p1.bottom = random(height/2);
       p2.top = random(height/2);
       p2.bottom = random(height/2);
       p3.top = random(height/2);
       p3.bottom = random(height/2);
 
    }  
  }
 
}
 
void success(Pipe test){
 
  if(birdy < test.top || birdy > height - test.bottom)
  {
    if(birdx > test.x && birdx < test.x + test.w)
    {
      gameOver = true;
    }
  }
}
class Pipe
{
  float top = random(height/3 + 200);
  float bottom = random(height/3 +200);
 
 
  float x = width + 150;
  float w = 70;
  color pipeColor = color(0, 255, 0);
 
  void pipe()
  {
    fill(pipeColor);
    rect(x, 0, w, top);
    rect(x, height-bottom, w, bottom);
   
    if(x < -100)
    {
     score += point;
     x = width;
     top = random(height/2);
     bottom = random(height/2);
    }
 
   
  }
 
 
}

ARDUINO CODE

const int trigPin=11; 
int echoPin=10; 
int safezone=10; 
//int dpin=13;
void setup() 
{
pinMode(trigPin,OUTPUT);
pinMode(echoPin,INPUT);
//pinMode(dpin,OUTPUT);
//digitalWrite(dpin,LOW);
Serial.begin(9600);
}
void loop()
{
long duration,cm; //DECLARE VARIABLES TO STORE SENSOR O/P
digitalWrite(trigPin,LOW); //MAKE THE TRIG PIN LOW
delayMicroseconds(2); //WAIT FOR FEW MICROSECONDS
digitalWrite(trigPin,HIGH); //NOW SET THE TRIG PIN
delayMicroseconds(5); //WAIT FOR FEW MICROSECONDS UNTIL THE TRIG PULSE IS SENT
digitalWrite(trigPin,LOW); //MAKE THE TRIG PIN LOW AGAIN
duration=pulseIn(echoPin,HIGH); //MAKE ECHO PIN HIGH AND STORE THE BOUNCED PULSE IN VARIABLE DURATION
cm=microsecondsToCentimeters(duration); 
long inch= cm/2.54;
//if(cm<safezone) 
//{
//digitalWrite(dpin,HIGH);
Serial.println(cm);
//delay(500);
//digitalWrite(dpin,LOW);
//}
}
long microsecondsToCentimeters(long microseconds) //SPEED OF SOUND IS 29 uSEC PER CM
{
return microseconds/29/2; //THE PULSE TRAVELS FROM THE SENSOR AND AGAIN COMES BACK SO WE DIVIDE IT BY 2 TO TAKE ONLY HALF OF THE TOTAL DISTANCE
}

SCHEMATICS

VIDEO DEMONSTRATION

Space Shooter Game – Extra Credit

For this extra credit project, I wanted to test my knowledge of the handshake between processing and arduino and so I came up with a space shooter game. It is a pretty basic game in which the space ship has to shoot the incoming meteoroids and if it shoots 10 of them the game is over.

 

Processing

The processing part is basically the interface of the game, which includes the start screen, the space ship, the asteroid and the whole shooting mechanism and also the end screen.

The game starts with the start screen in which the player clicks within a box to start playing.

The code basically spawns random sizes of asteroids, that fall at random speeds too. If the player is able to shoot 10 asteroids, the game is over and the player is prompted to either restart the game or click on game over to return to the start screen.

Processing Code:

import processing.serial.*;
Serial myPort;
ArrayList<Asteroid> asteroids = new ArrayList<Asteroid>(); //gives the list of asteroids
Player player; //player object
boolean shoot = false; // ensures that the player only shoots when commanded
ArrayList<Player.Bullet> bullets = new ArrayList<Player.Bullet>(); //bullet list
float timer = 0;
float timerlength  = 4000;
boolean game_over = false; 
boolean start = false; 
int count = 0; 
int currentButtonState = 0;
int prevButtonState = 0;
float mover = width/2; 

void setup()
{
  size(1280, 960);
  
  imageMode(CENTER);
  //asteroids.add(new Asteroid(random(width*0.25, width*0.75), 0, int(random(1, 3)))); //initialising the list of asteroids to spawn in between the roads of the game
  player = new Player();
  printArray(Serial.list());
  String portname=Serial.list()[6];
  println(portname);
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  
}

void draw()

{
  PImage bg;  
  bg = loadImage("space.jpeg");
  bg.resize(int(width),int(height));
  background(bg); //background is the top down view of a road
  if (start == false)
  {
    textAlign(BASELINE);
  rectMode(CENTER);
  fill(255);
  stroke(230,153,0);
  rect(width/2,height/2,700,500,10);
  rect(width/2, height/2,680,480,10);
  
  fill(0);
  textSize(50); 
  text("Welcome", 480, 410);   
  fill(255);
  rect(625,580,600,100,10);
  fill(0);
  text("Click to Play", 420, 610);
  if ((mouseX >= 325 && mouseX <= 925) && (mouseY >= 530 && mouseY <= 630) && (mousePressed == true))
   {
     start = true;
   }
  }
  
  else{  
  if(game_over == false)
  {
   
    Player_Mechanics();
    Asteroid_Mechanics(); 
    Shoot();
    Mover();
    
    if( millis() > timer)
    {
      asteroids.add(new Asteroid(random(width*0.25, width*0.75), 0, int(random(1, 3)))); //initialising the list of asteroids to spawn 
      timerlength = random(1000,5000);
      timer = millis() + timerlength;
    }
  }
  
  else{
   textAlign(BASELINE);
  rectMode(CENTER);
  fill(255);
  stroke(230,153,0);  
  rect(width/2,height/2,700,500,10);
  rect(width/2, height/2,680,480,10);
  
  fill(0);
  textSize(50); 
  stroke(0);
  text("Game Over!", 420, 410);   
  fill(255);
  rect(625,580,600,100,10);
  fill(0);
  text("Restart", 420, 610);
  if ((mouseX >= 325 && mouseX <= 925) && (mouseY >= 530 && mouseY <= 630) && (mousePressed == true))
   {
     game_over = false;
     count = 0; 
   }
   
   if ((mouseX >= 325 && mouseX <= 925) && (mouseY >= 330 && mouseY <= 430) && (mousePressed == true))
   {
     start = false;
   }
   
  }
  }
}

void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    println(s);
    int values[]=int(split(s,','));
    if (values.length==3){
      currentButtonState=(int)values[0];
      prevButtonState=(int)values[1];
      mover = map(values[2], 0, 1023, player.size/2, width-player.size/2);
    }
  }
  myPort.write("\n");
}

void Player_Mechanics()
{
  
  player.drawPlayer();  //draws the Player on Screen
  
  for(int i =0; i< bullets.size(); i++)
  {
    
    bullets.get(i).draw_Bullet();
    bullets.get(i).shoot_Bullet();  //if bullets are present, draws them and shoots them
    if(bullets.get(i).bullet_posY_1 < 0 )
      bullets.remove(i); //removes the bullet once they are out of frame
  }
  

}


void Asteroid_Mechanics()
{
  for (int i = 0; i < asteroids.size(); i++)
  {   
    asteroids.get(i).drawAsteroid();
    asteroids.get(i).moveAsteroid(); //draws and moves asteroids on screen
    if(asteroids.get(i).posY > height + asteroids.get(i).size)
      asteroids.remove(i);  //removes the asteroids once they are out of frame
    if( bullets.size() > 0 && asteroids.size() > 0 )
    {
      for(int j=0; j<bullets.size(); j++)
      {
        if( bullets.size() > 0 && asteroids.size() > 0 )
        {
          if(asteroids.get(i).vicinty_check(bullets.get(j).bullet_posX,bullets.get(j).bullet_posY_2))
            {
              asteroids.remove(i); //destroys the asteroid and removes it once bullet touches it
              count++;
            }
        }
      }
    }
  }
  if (count == 10){
    game_over = true;
  }   
}

void keyPressed()
{
  if (key == ' ')
  {
    asteroids.add(new Asteroid(random(width*0.25, width*0.75), 0, int(random(1, 3)))); //spawns an asteroid
  }

  if (key == 'a')
  {
    player.moveLeft(); //player goes left
  }

  if (key == 'd')
  {
    player.moveRight(); //player goes right
  }
  
  if (key == 'f')
  {
    bullets.add(player.new Bullet(0));  //shoots bullets
  }
}

void Shoot()
{
  if (currentButtonState == 1 && prevButtonState == 0) {
    bullets.add(player.new Bullet(0));     
    println("cheeky");
  }
}


void Mover()
{
  player.posX = mover;
}
class Asteroid {

  float posX;
  float posY;
  int speed = (int)random(2,6);
  int size;
  PImage asteroid;




  Asteroid(float x, float y, int s)
  {
    posX = x;
    posY = y;
    size = s*100;
    asteroid = loadImage("asteroid_brown.png");
    imageMode(CENTER);
  }

  void drawAsteroid()
  {

    asteroid.resize(size, 0);
    image(asteroid, posX, posY);  //resizes and draws the asteroid
  }

  void moveAsteroid()
  {
    posY += speed;  //moves the asteroid
  }

  boolean vicinty_check(float x, float y)
  {
    if ((x < posX+size/2 && x > posX-size/2) && (y < posY+size/2 && y > posY-size/2))  //checks if anything exists in the vicintiy of the asteroid's body
      return true;
    else
      return false;
  }
}
class Player {

  public float posX = width/2;  
  public float posY = height-100;
  PImage player;  
  int movement=20;
  int size =100;


  Player()
  {

    player = loadImage("Spaceship_tut.png");
    imageMode(CENTER);
  }



  void drawPlayer()
  {
    player.resize(size, 0);
    pushMatrix();
    translate(posX, posY);
    //rotate(radians(270));
    image(player, 0, 0);
    popMatrix(); //resizes and rotates the image of the player on screen so that it is appropriate for the game
  }

  void moveLeft()
  {
    
    if (posX > size/2)
      posX -= movement; //player moves left
  }

  void moveRight()
  {
    
    if (posX < width-size/2)
      posX += movement; //player moves right
  }


  class Bullet {    //nested bullet class in player class

    float  bullet_posX = posX ;
    float  bullet_posY_1 = posY - size/2; 
    float  bullet_size = size * 0.1; 
    float  bullet_posY_2 = posY - size/2 - bullet_size; 
    int bullet_speed = 20; 


    Bullet(float y)
    {
      bullet_posY_1 -= y;
      bullet_posY_2 -= y;    //assigns intial position to bullet
    } 
    void draw_Bullet()
    {
      stroke(102,255,102);
      strokeWeight(6);
      line(bullet_posX, bullet_posY_1, bullet_posX, bullet_posY_2);  //draws a line for a bullet
    } 

    void shoot_Bullet()  

    {
      bullet_posY_1 -= bullet_speed;
      bullet_posY_2 -= bullet_speed;  //moves bullet
    }
  }
}

 

Game Display

Arduino

The Arduino part involves the controls for the game in which the potentiometer is used to move the spaceship around and the push button is used to shoot the missiles from the spaceship.

 

Arduino Code:

int buttonPin = 2;
int prevButtonState = LOW;

void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  Serial.println("0,0");
}

 void loop() {
  while (Serial.available()) {
    if (Serial.read() == '\n') {
      int currentButtonState = digitalRead(buttonPin);
      delay(1);      
      Serial.print(currentButtonState);
      Serial.print(',');
      Serial.print(prevButtonState);
      Serial.print(',');      
      prevButtonState = currentButtonState;
      int mover = analogRead(A0);
      delay(1);
      Serial.println(mover);
    }
  }
  
  //Serial.println(sensor);

}

 

Circuit:

Arduino Circuit

Videos:

This is the video of me showing the way the game works:

This is a video of me actually playing the game:

Difficulties:

In certain instances, I felt that the button was not responding in the way I wanted it to but I believe that is primarily because I hadn’t plugged it well or the communication of information was slow.

Overall:

This project was actually really fun and it made me feel so cool to create my own joystick for my game. This has also motivated me quite a lot for my final project which I am really looking forward to!

Extra Arduino Game

Assignment:

This week we were given the option of creating a game with the Arduino and I decided to continue with my favorite Processing game thus far, my F1 simulator. I wanted to make a controller that would be integrated into the game.

 

Game Controller:

There are three main inputs in a car (a simplified automatic one anyways), steering, gas, and acceleration. My game already had these inputs but steering was in essence binary (full left, neutral, full right). I decided that analog input could make for much more fun steering and in addition to gas/brake buttons I could make a F1 car controller.

For the steering I used the potentiometer. I had to rework all my code for how the car was steered as it was no longer left or right, but rather any value from full left to full right and anywhere in-between. I ended up checking which way the potentiometer was facing and mapping the annual acceleration of the car off of this.

I also added a brake and gas button. These were super easy to implement as they behaved exactly the same as if I was pressing the up or down arrow in the keyboard controls so all I had to was change to binary values if they were on or off.

Finally I wanted something a bit extra than just inputs, also outputs that could make the player feel more like they were in a car. I decided to add two LEDs, a green one that would light up when pressing the gas, and a red one that would light up when braking, or flash when the car crashed like hazard lights. This allowed me to try the no delay blinking code as well.

Circuit

Code

Arduino Code

const int brakeLed = 5;
const int forwardLed = 4;
const int forwardButton = 2;
const int brakeButton = 3;
const int sensorPin = A0;

int forward = 0;
int brake = 0;
int crash = 0;
long timer = 0;
int timerLength = 500;
bool onOff = false;

void setup() {
  Serial.begin(9600);
  Serial.println("0,0");
  pinMode(brakeLed, OUTPUT);
  pinMode(forwardLed, OUTPUT);
  pinMode(forwardButton, INPUT);
  pinMode(brakeButton, INPUT);
}

void loop() {
  while (Serial.available()) {
    forward = Serial.parseInt();
    brake = Serial.parseInt();
    crash = Serial.parseInt();
    if (Serial.read() == '\n') {
      if (crash) {
        if (millis() > timer) {
          onOff = !onOff;
          digitalWrite(brakeLed, onOff);
        digitalWrite(forwardLed, LOW);
          timer = millis() + timerLength;
        }
      }
      else{
        digitalWrite(forwardLed, forward);
        digitalWrite(brakeLed, brake);
      }
      int forwardToggle = digitalRead(forwardButton);
      delay(1);
      int brakeToggle = digitalRead(brakeButton);
      delay(1);
      int steeringInput = analogRead(sensorPin);
      delay(1);
      Serial.print(forwardToggle);
      Serial.print(',');
      Serial.print(brakeToggle);
      Serial.print(',');
      Serial.println(steeringInput);
    }
  }
}

Processing Code

import processing.sound.*;

//======= Global variables ========
int gameMode = 0; //0 is main menu, 1 select your car, 2 running game, 3 crash, 4 controls menu, 5 credits
Team teams[] = new Team[10];
int teamSelector = 0;  //Which team from array is selected
int[][] teamDict = {{7, 0, 7, 0, 0}, {8, 1, 8, 0, 1}, {5, 2, 5, 0, 2}, {4, 3, 4, 0, 3}, {0, 4, 0, 0, 4}, {2, 5, 2, 1, 0}, {1, 6, 1, 1, 1}, {6, 7, 6, 1, 2}, {9, 8, 9, 1, 3}, {3, 9, 3, 1, 4}}; //Dictonary containing index of car sprite, associated team image sprite index, team name index, menu row, menu col

//====== Team Selection Menu Variables
PImage teamMenuImg;


//====== Trak Menu Variables
//  PImage track[][] = new PImage[10][10];  //For tile system
//float tileWidth = 2560;  //For tile system
PImage map;
float trackScale = 1; //What percent of original size should track be drawn

//====== Main Game Variables
float rotation = PI;  //Current angle
float speed = 0;  //Current speed
float maxSpeed = 500;  //Max speed on the track
float sandMaxSpeed = 20;  //Max speed off the track
float posX = -4886.6123;  //0,0 is top left of track , values increase negative as they are reversed
float posY = -1254.3951;

float acceleration = 5;  //How fast the car speeds up on track
float sandAcceleration = 1;  //How fast the car speeds up in sand
float brakeDeacceleration = 10;  //How quick the car stops when braking on track
float coastDeacceleration = 2;  //How quick the car stops when no power
float sandDeacceleration = 15;  //How quick the car stops in sand
float angularAcceleration = PI/20;  //How fast the car turns
boolean reverse = false;

float carScale = 0.3; //What percent of original size should car be drawn

//Keyboard inputs
boolean forward = false;
boolean brake = false;
boolean left = false;
boolean right = false;

//Sound
SoundFile accSound;
float accSoundAmp = 0;
float soundRate = 0.5;

//Timing
int passedTime;  //How long has passed since saved time mark
int savedTime;  //Savea time to start timer
boolean activeTimer = false; //Set to false, becomes active when crossing start line or false if reversed over
int bestTime = -1;

//Menu files
PImage controls;
PImage credits;

//Main menu variables  
  int numButtons = 3;
  int activeButton = 0; // 0 for start, 1 for controls, 2 for credits
  int buttonWidth = 200;
  int buttonHeight = 100;
  int buttonSpacing = 50;
  int buttonYOffset = 100;
  String buttonContent[] = {"Start Game","Controls","Credits"};
  float buttonX;
  float buttonY;
  
//Arduino game control variables
import processing.serial.*;
Serial myPort;
boolean crash = false;

void setup() {
  fullScreen();

  //Set up the team array
  //=======================================================================================
  PImage[] carSprites;
  PImage[] teamSprites;
  String[] nameArray = {"McLaren F1 Team", 
    "Scuderia AlphaTauri Honda", 
    "Mercedes-AMG Petronas F1 Team", 
    "ROKiT Williams Racing", 
    "Haas F1 Team", 
    "BWT Racing Point F1 Team", 
    "Scuderia Ferrari", 
    "Alfa Romeo Racing ORLEN", 
    "Aston Martin Red Bull Racing", 
    "Renault F1 Team"
  };
  //Alfa Romeo, Red Bull, Racing Point, Haas, Mclaren, Mercedes, AlphaTauri, Ferrari, Renault, Williams

  //Set sprite sheets
  carSprites = getCarSpriteSheet("SpriteSheetCars.png");  //Load the car sprite sheet into sprites
  teamSprites = getTeamSpriteSheet("Teams.png");  //Load the team sprite sheet into sprites

  //Set teams array with appropiate info
  for (int i = 0; i < 10; i++) {
    Team newTeam = new Team();
    newTeam.setName(nameArray[teamDict[i][2]]);  //Set team name
    newTeam.setCarImg(carSprites[teamDict[i][0]]);  //Set team img
    newTeam.setTeamImg(teamSprites[teamDict[i][1]]);  //Set team car img
    teams[i] = newTeam;
  }

  //=======================================================================================

  //Load menu imgs
  teamMenuImg = loadImage("Teams.png");
  controls = loadImage("Controls.png");
  credits = loadImage("Credits.png");

  //=======================================================================================

  //Load map
  map = loadImage("Track.png");

  //=======================================================================================
  //Load sound
  accSound = new SoundFile(this, "acc.wav");
  accSound.loop();
  accSound.amp(accSoundAmp);
  accSound.rate(soundRate);
  
  //Start lap timer
  savedTime = millis();
  
  //Start serial communication with controller
  String portname=Serial.list()[1];
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
}

void draw() {
  //Main Gamemode Control selector
  switch(gameMode) {
  case 0:
    mainMenu();
    break;
  case 1:
    teamMenu();
    break;
  case 2:
    runGame();
    break;
  case 3:
    crash();
    break;
  case 4:
    controls();
    break;
  case 5:
    credits();
    break;
  }
}


//When all game cariables need to be reset to start status
void resetVariables(){
  accSound.amp(0);
  forward = brake = right = left = false;
  activeTimer = false;
  speed = 0;
  gameMode = 0;
  posX = -4886.6123;  //0,0 is top left of track , values increase negative as they are reversed
  posY = -1254.3951;
  rotation = PI;
  crash = false;
}


void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    println(s);
    int values[]=int(split(s,','));
    if (values.length==3){
      if(values[0] == 1 && values[1] == 1){
        forward = false;
        brake = false;
      }
      else if (values[0] == 1){
        forward = true;
      }
      else if (values[1] == 1){
        brake = true;
      }
      else if (values[0] == 0 && values[1] == 0){
        forward = false;
        brake = false;
      }
      
      
      int steering = values[2];
      //Turn left
      if(steering > 1023/2){
        left = true;
        right = false;
        angularAcceleration = map(values[2],1023/2,1023,0, PI/20);
      }
      else if(steering < 1023/2){
        left = false;
        right = true;
        angularAcceleration = map(values[2],1023/2,0,0, PI/20);
      }
    }
  }
  println(crash);
  myPort.write(int(forward)+","+int(brake)+","+int(crash)+"\n");
}

 

Results

[Week 12] Final project proposal – Ngoc and Maaz

Game concept

In our previous post, Maaz and I mentioned that we would be using Processing and Arduino together to make a game for our final project which would be similar to Tetris. However, both of us were not very satisfied with how we were using the sensors in our game. We thought we could find some ways to better utilize the Arduino components. Additionally, after the discussion session on Monday, we were pretty sure that we had to make tweaks to the game play.

We now have a new version of our game. This version is very different from Tetris but it uses most of the sensors in the same way as the previous version did. The distance sensor continues to be the most important resistor, while we have added a few new features. This version is an NYUAD-themed game, in which the player playing the game sees certain objects falling down the screen. These objects will be of two categories: objects which the player should catch and objects which the player should avoid. The player controls the game using the breadboard which has the distance sensor mounted on it (the entire things acts as a “remote control”). Towards the right and left of the remote control will be a frame (made of cardboard for instance). The two sides of this frame represent the endpoints of the game screen, and they help us determine how far the distance sensor (and hence the remote control) is from one end of the screen. Using this “remote control”, the player’s position can also be displayed on the screen for the player to figure out how close/far away they are from objects that are to be caught/avoided.

The ground rules of the game are as the following:

  • Just like in the previous version of our game, this version will have multiple levels of varying difficulty. We plan to have four levels corresponding to four academic years, with each succeeding level harder than the previous one.
  • The player has to maintain two metrics of performances: academic performance and well-being. There are certain objects that are beneficial and objects that are harmful to a performance. You need to catch the good objects (which will increase your performance) and avoid the bad ones (which will decrease your performance).
  • Initially, both performances start at 50% and you need to take them both to 100% to finish the year and advance to the next academic year. If either of the performances reaches to 0, you fail the year.
  • If you fail, you are presented with 3 options:
    • You can either restart college (restarting the entire game)
    • Or you can restart the academic year (restarting that particular level)
    • Or you can drop out (exiting the game)
  • If you finishing all four academic years, you win the game (congrats on graduating)
    • You will be given a diploma and introduced to “other games” (Career, Graduate schools, might be coming soon (no they aren’t, we are not doing those for real))

Arduino – Processing communication

  • Distance sensor is implemented as a remote control:
    • The Arduino program calculates how far the remote control is from a vertical surface
    • The distance is sent to Processing which will map the distance into the player’s horizontal coordinate
    • An icon representing the player’s position on the Processing screen is updated accordingly
  • Processing will check for collision with items. If there is a collision, a signal is sent to Arduino to play a sound on the buzzer
  • When the player is presented with a screen that has options (for example, the starting screen can have Instructions, Start game, the ending screen can have Restart college, Restart the year, Drop out), the player can use the potentiometer on the Arduino to traverse the options and press a button when the desired option is selected to proceed.
  • Processing receives the signal from the potentiometer and maps it to a range to decide which option is currently selected by the player and communicates this back to the player by highlighting the option.
  • Two tricolor LEDs on the Arduino are used to communicate the player’s current performances, one to represent academic performance and the other to represent well-being. If the player’s performance in either is fulfilled (reaches 100), the LED(s) turns green; if performance is adequate, the LED(s) turns blue/yellow (?); and if performance is low (approaching 0), the LED(s) turns red.

Exercises: Serial Comms

Exercise 1: I essentially modified the starter code such that the y position remained fixed in the middle of the screen.

Arduino:

int pot = A0;
 
void setup() {
  Serial.begin(9600);
  Serial.println("0");
  pinMode(pot, INPUT);
}
 
void loop() {
  while (Serial.available()) {
    if (Serial.read() == '\n') {
      int sensor = analogRead(A0);
      Serial.println(sensor);
    }
  }
}

Processing:

import processing.serial.*;
Serial myPort;
int xPos=0;
int yPos=height/2;
 
void setup(){
  size(960,720);
  printArray(Serial.list());
  String portname=Serial.list()[1];
  println(portname);
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
}
 
void draw(){
  background(255);
  ellipse(xPos,yPos,30,30);
}
 
void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    println(s);
    int val=int(s);
      xPos=(int)map(val,0,1023,0, width);
  }
  myPort.write("\n");
}

 

Exercise 2: I used the mouse speed from Processing to determine the brightness of the LED in Arduino.

Arduino code:

int ledPin = 5;
int bright;
 
void setup() {
  Serial.begin(9600);
  Serial.println("0");
  pinMode(ledPin, OUTPUT);
}
 
void loop() {
  while (Serial.available()) {
    bright = Serial.parseInt();
    if (Serial.read() == '\n') {
      analogWrite(ledPin, bright);
      Serial.print("\n");
    }
  }
}

Processing Code:

import processing.serial.*;
Serial myPort;
float mouseSpeed;
float smoothSpeed;
 
void setup(){
  size(960,720);
  printArray(Serial.list());
  String portname=Serial.list()[2];
  println(portname);
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
}
 
void draw(){
  background(255);
  ellipse(mouseX, mouseY, 25, 25);
  mouseSpeed =  5 * dist(mouseX, mouseY, pmouseX, pmouseY);
  smoothSpeed = lerp(smoothSpeed, mouseSpeed, 0.1);
  println(smoothSpeed);
}
 
void serialEvent(Serial myPort){
  float val = map(smoothSpeed, 0, 400, 0, 255);
  myPort.write((int)val + "\n");
}

 

Exercise 3: The photoresistor affected the wind direction and each time the ball bounced on Processing, I wrote to the serial to communicate to Arudino that the LED should light up. I originally used a photoresistor, but it felt a bit clunky. I still find the response in the wind vector kind of slow but find the movement more intuitive than the potentiometer.

Arduino Code:

int phot = A0;
int led = 2;
int bounce = 0;
int pastVal;
int val;
void setup() {
  Serial.begin(9600);
  Serial.println("0,0");
  pinMode(led, OUTPUT);
  pinMode(phot, INPUT);
  val = analogRead(phot);
  pastVal = val;

}

void loop() {

  while (Serial.available()) {
    bounce = Serial.parseInt();
    if (bounce == 1) {
      digitalWrite(led, HIGH);
    } else {
      digitalWrite(led, LOW);
    }
    if (Serial.read() == '\n') {
      

      val = analogRead(phot);
      if (pastVal != val) {
        if (val >= 34) {
          Serial.println(1);
        } else {
          Serial.println(-1);
        }
        pastVal = val;
      }
      else {
        Serial.println(0);
      }
      }
     
    }
  }

 

Processing Code:

PVector velocity;
PVector gravity;
import processing.serial.*;
Serial myPort;

PVector position;
PVector acceleration;
PVector wind;
float drag = 0.99;
float mass = 50;
float hDampening;
int bounce = 0;

void setup() {
  size(640,360);
  noFill();
  position = new PVector(width/2, 0);
  velocity = new PVector(0,0);
  acceleration = new PVector(0,0);
  gravity = new PVector(0, 0.5*mass);
  wind = new PVector(0,0);
  hDampening=map(mass,15,80,.98,.96);
  
  String portname=Serial.list()[2];
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
}

void draw() {
  background(255);
    velocity.x*=hDampening;
  applyForce(wind);
  applyForce(gravity);
  velocity.add(acceleration);
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);
  ellipse(position.x,position.y,mass,mass);
  if (position.y > height-mass/2) {
      velocity.y *= -0.9;  // A little dampening when hitting the bottom
      position.y = height-mass/2;
      bounce = 0;
    }
}
  
void applyForce(PVector force){
  // Newton's 2nd law: F = M * A
  // or A = F / M
  PVector f = PVector.div(force, mass);
  acceleration.add(f);
}

void keyPressed(){

  if (key==' '){
    mass=random(15,80);
    position.y=-mass;
    velocity.mult(0);
  }
}

void serialEvent(Serial myPort){
  
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  
  if (s!=null) {
    int windVal = int(s);
    println(windVal);
    if (wind.x >= -1 || wind.x <= 1) {
      wind.x = windVal;
    }
  }
  
  if (round(velocity.y) < 0) {
    bounce = 1;
  } else {
    bounce = 0;
  }
  myPort.write(bounce + "\n");
}

 

 

 

 

 

Final Project Idea

For my midterm project i have several ideas, which i can implement using atduino and processing .

The first idea is a “therapy app” . It will include  different options and modes for different aims. Like relax or otherwise focusing.

The second idea is some sort  of the game travelling story, where you can make some exercises( small interactive games) to continue and reach the end of the story.  The theme i’m gonna choose is ecology to pay audience attention to a problems are happening now.

[Serial Communication Excercise] Cole and Minh

Exercise 1:

Excercise 2

Exercise 3:

const int ledPin = 11;
int brightness = 0;
const int sensorPin = A0;
 
void setup() {
  Serial.begin(9600);
  Serial.println("0,0");
  pinMode(ledPin, OUTPUT);
}
 
void loop() {
  while (Serial.available()) {
    int onOff = Serial.parseInt();
    if (Serial.read() == '\n') {
      digitalWrite(ledPin, onOff);
      int sensor = analogRead(sensorPin);
      delay(1);
      Serial.println(sensor);
    }
  }
}


//PROCESSING CODE
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);
  ellipse(position.x,position.y,mass,mass);
  fill(255,255,0);
  if (position.y > height-mass/2) {
      velocity.y *= -0.9;  // A little dampening when hitting the bottom
      position.y = height-mass/2;
      onOff = true;
  }
  else{
    onOff = false;
  }
}
 
void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  int val = parseInt(s);
  if (s!=null){
      wind.x=map(val,0,1023,-2, 2);  //2 instead of 1 to make it stronger
  }
  myPort.write(int(onOff)+"\n");
}
  
void applyForce(PVector force){
  // Newton's 2nd law: F = M * A
  // or A = F / M
  PVector f = PVector.div(force, mass);
  acceleration.add(f);
}

void keyPressed(){
  if (keyCode==LEFT){
    wind.x=-1;
  }
  if (keyCode==RIGHT){
    wind.x=1;
  }
  if (key==' '){
    mass=random(15,80);
    position.y=-mass;
    velocity.mult(0);
  }
}

Video for exercise 3: