Midterms – User Testing

Midterms – User Testing

The past two weeks were dedicated to creating our midterm projects, using the capabilities of both the Arduino and Processing to create a wide scale project that others could use for utility, entertainment, or both. My partner Melody and I decided to take the entertainment route; because I had a better understanding of Processing, we decided that I would dedicate my coding abilities to this project. At first, Melody and I had a bit of trouble thinking of ideas for our project, but through the sharing of our childhood backgrounds, we came to an interesting conclusion: we were going to create the old retro game Pong.

Continue reading

/*
 *
 * THE ULTIMATE PONG ARCADE GAME
 * code by Zane Fadul
 */

import processing.serial.*;
import processing.sound.*;

//******************************************************************Controller Variables
Serial controller;
int valueFromController = 79; //putting a random assignment
int player1Values;
int player2Values;
int down;
int up;
int b;
int a;
int[] controllerValues;

//***********************************************************************Sound Variables
SoundFile intro;
SoundFile menu;
SoundFile buttonClick;
SoundFile battle;
SoundFile transitionSound;
SoundFile ballOut;
SoundFile win;
SoundFile ability;
//*********************************************************************Graphic Variables
PFont infoFont;
PFont titleFont;
int heightPixels;
int widthPixels;
int startTime;

// Star Field Graphic used by:
// Daniel Shiffman
// http://codingtra.in
// http://patreon.com/codingtrain
// Code for: https://youtu.be/17WoOqgXsRM
class Star {
  float x;
  float y;
  float z;
  float pz;

  Star() {
    x = random(-width/2, width/2);
    y = random(-height/2, height/2);
    z = random(width/2);
    pz = z;
  }

  void update() {
    z = z - speed;
    if (z < 1) {
      z = width/2;
      x = random(-width/2, width/2);
      y = random(-height/2, height/2);
      pz = z;
    }
  }

  void show() {
    strokeWeight(1);
    fill(255);
    noStroke();
    float sx = map(x / z, 0, 1, 0, width/2);
    float sy = map(y / z, 0, 1, 0, height/2);
    float px = map(x / pz, 0, 1, 0, width/2);
    float py = map(y / pz, 0, 1, 0, height/2);
    pz = z;
    pushMatrix();
    stroke(255);
    translate(width/2, height/2);
    line(px, py, sx, sy);
    popMatrix();
  }
}
int speed = height/30;
Star[] stars = new Star[800];

//Intro Sequence Variables
float dotX(float dotT) {
  return sin(dotT/10) * heightPixels/5;
}
float dotY(float dotT) {
  return cos(dotT/10) * heightPixels/5;
}
float dotT = 0;
float alpha = 0;
boolean beginTitle = false;
float scaleBall = 2;

//Title Screen Variables
class Drop {
  float x = random(0, width);
  float y = random(height);
  float xSpeed = random(4, 10);

  void fall() {
    x = x + xSpeed;

    if (x > width) {
      y = random(height);
      x = random(-500, -100);
    }
  }

  void show() {
    stroke(160);
    strokeWeight(1);
    line(x, y, x + height/10, y);
  }
}
Drop[] drops = new Drop[100];

//Game Variables
class Transition {
  float x = random(0, width);
  float y = random(height);
  float xSpeed = random(width/5, width/2);

  void fall() {
    x = x + xSpeed;

    if (x > width) {
      y = random(height);
      x = random(-500, -100);
    }
  }

  void show() {
    stroke(160);
    strokeWeight(1);
    line(x, y, x + height/10, y);
  }
}
Transition[] particles = new Transition[100];
int transitionCount = 0;

//Ability Bars
void abilityBar1(int charge, float spark) {
  switch(charge) {
  case 0:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    break;

  case 1:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, width/80, height/40);
    break;

  case 2:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 2*width/80, height/40);
    break;

  case 3:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 3*width/80, height/40);
    break;

  case 4:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 4*width/80, height/40);
    break;

  case 5:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 5*width/80, height/40);
    break;

  case 6:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 6*width/80, height/40);
    break;

  case 7:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 7*width/80, height/40);
    break;

  case 8:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 8*width/80, height/40);
    break;

  case 9:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, height/80, 9*width/80, height/40);
    break;

  case 10:
    noStroke();
    rectMode(CORNER);
    spark = random(170, 255);
    fill(#0063FF, spark);
    rect(3.3*width/4, height/80, width/8, height/40);
    break;
  }
}
void abilityBar2(int charge, float spark) {
  switch(charge) {
  case 0:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    break;

  case 1:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, width/80, height/40);
    break;

  case 2:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 2*width/80, height/40);
    break;

  case 3:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 3*width/80, height/40);
    break;

  case 4:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 4*width/80, height/40);
    break;

  case 5:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 5*width/80, height/40);
    break;

  case 6:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 6*width/80, height/40);
    break;

  case 7:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 7*width/80, height/40);
    break;

  case 8:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 8*width/80, height/40);
    break;

  case 9:
    noStroke();
    rectMode(CORNER);
    fill(170);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    fill(#0063FF);
    rect(3.3*width/4, 77*height/80, 9*width/80, height/40);
    break;

  case 10:
    noStroke();
    rectMode(CORNER);
    spark = random(170, 255);
    fill(#0063FF, spark);
    rect(3.3*width/4, 77*height/80, width/8, height/40);
    break;
  }
}
float spark1 = 255;
float spark2 = 255;

//Lives
void printP1Lives(int lives, int colorIndex) {
  switch(colorIndex) {
  case 1:
    colorIndex = #B2D8FF;
    break;
  case 2:
    colorIndex = #FF0000;
    break;
  case 3:
    colorIndex = #0700FF;
    break;
  case 4:
    colorIndex = #B600FF;
    break;
  case 5:
    colorIndex = #1BFF08;
    break;
  case 666:
    colorIndex = 0;
    break;
  }
  switch(lives) {
  case 3:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(255);
    ellipse(3*width/8, height/40, height/40, height/40);
    ellipse(width/2, height/40, height/40, height/40);
    ellipse(5*width/8, height/40, height/40, height/40);
    break;

  case 2:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(255);
    ellipse(3*width/8, height/40, height/40, height/40);
    ellipse(width/2, height/40, height/40, height/40);
    fill(0);
    ellipse(5*width/8, height/40, height/40, height/40);
    break;

  case 1:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(255);
    ellipse(3*width/8, height/40, height/40, height/40);
    fill(0);
    ellipse(width/2, height/40, height/40, height/40);
    ellipse(5*width/8, height/40, height/40, height/40);
    break;

  case 0:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(0);
    ellipse(3*width/8, height/40, height/40, height/40);
    ellipse(width/2, height/40, height/40, height/40);
    ellipse(5*width/8, height/40, height/40, height/40);
    break;
  }
}

void printP2Lives(int lives, int colorIndex) {
  switch(colorIndex) {
  case 1:
    colorIndex = #B2D8FF;
    break;
  case 2:
    colorIndex = #FF0000;
    break;
  case 3:
    colorIndex = #0700FF;
    break;
  case 4:
    colorIndex = #B600FF;
    break;
  case 5:
    colorIndex = #1BFF08;
    break;
  case 666:
    colorIndex = 0;
    break;
  }
  switch(lives) {
  case 3:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(255);
    ellipse(3*width/8, 39*height/40, height/40, height/40);
    ellipse(width/2, 39*height/40, height/40, height/40);
    ellipse(5*width/8, 39*height/40, height/40, height/40);
    break;

  case 2:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(255);
    ellipse(3*width/8, 39*height/40, height/40, height/40);
    ellipse(width/2, 39*height/40, height/40, height/40);
    fill(0);
    ellipse(5*width/8, 39*height/40, height/40, height/40);
    break;

  case 1:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(255);
    ellipse(3*width/8, 39*height/40, height/40, height/40);
    fill(0);
    ellipse(width/2, 39*height/40, height/40, height/40);
    ellipse(5*width/8, 39*height/40, height/40, height/40);
    break;

  case 0:
    strokeWeight(4);
    stroke(colorIndex);
    shapeMode(CENTER);
    fill(0);
    ellipse(3*width/8, 39*height/40, height/40, height/40);
    ellipse(width/2, 39*height/40, height/40, height/40);
    ellipse(5*width/8, 39*height/40, height/40, height/40);
    break;
  }
}

//End Game Variables
int endGameTimer = 0;

//************************************************************************Button Objects
class Button
{
  int buttonIndex;
  String text;
  float xPos;
  float yPos;


  Button(int buttonIndex, String text, float xPos, float yPos)
  {
    this.buttonIndex = buttonIndex;
    this.text = text;
    this.xPos = xPos;
    this.yPos = yPos;
  } 

  int getButtonIndex() {
    return buttonIndex;
  }

  String getButtonName() {
    return text;
  }

  void changeText(String text) {
    this.text = text;
  }

  void display() {
    boolean bool = checkForSelected(valueFromController, buttonIndex);
    if (bool == true) { //IF SELECTED
      rectMode(CENTER);
      strokeWeight(width/100);
      stroke(255);
      fill(0);
      rect(xPos, yPos, width/5, height/12);
      fill(255);
      textAlign(CENTER);
      textFont(infoFont);
      text(text, xPos, yPos  + height/48, width/5, height/12); //ATTEMPTS TO PRINT TEXT ON A BOX
    }
    if (bool == false) { //IF NOT SELECTED
      rectMode(CENTER);
      strokeWeight(width/200);
      stroke(255);
      fill(0);
      rect(xPos, yPos, width/5, height/12);
      fill(255);
      textAlign(CENTER);
      textFont(infoFont);
      text(text, xPos, yPos + height/48, width/5, height/12);
    }
  }
}

boolean checkForSelected(int valueFromController, int buttonIndex) {
  if (valueFromController == buttonIndex) {
    return true;
  } else {
    return false;
  }
}

//Main Menu Buttons
Button startMatchButton;
Button addUserButton;
Button changeUserColorButton;
Button howToPlayButton;
Button selectUser1Button;
Button selectUser2Button;
Button playGameButton;
boolean player1Selected = false;
boolean player2Selected = false;

//************************************************************************Data Variables
PrintWriter userDatabase;
String[] userData;

//**********************************************************************Switch Variables
//Screen Switches
boolean gameLoaded = false;
boolean gameIntro = false;
boolean introSkip = false;
boolean titleScreen = false;
boolean listUsers = false;
boolean selectUserToAdd = false;
boolean createUser = false;
boolean chooseColor = false;
boolean firstTimeAdd = false;
boolean selectUserToColor = false;
boolean selectUserToDelete = false;
boolean playGame = false;
boolean transition = false;
boolean gameOver = false;

//Title Screen Button Switches
boolean startMatch = false;
boolean changeUserColor = false;
boolean deleteUser = false;
boolean howToPlay = false;

//Ability Switches
boolean ability1Used = false;
boolean ability2Used = false;

//**************************************************************************User Objects
class User
{
  //Instance Variables
  String username;
  int rank = 1;
  int preferredColor;
  String data;

  //Constructor Declaration of Class
  User(String username, int rank, int preferredColor)
  {
    this.username = username.toUpperCase();
    this.rank = rank;
    this.preferredColor = preferredColor;
  }

  String getUsername()
  {
    return username;
  }
  int getRank() {
    return rank;
  }
  int getPreferredColor() {
    return preferredColor;
  }
  void addRank() {
    rank += 1;
  }
  void setUsername(String username) {
    this.username = username.toUpperCase();
  }
  void setPreferredColor(int preferredColor) {
    this.preferredColor = preferredColor;
  }
}

/* Type Mismatch when incrementing objects to the list, will redo using simply strings
 Object createNewUserFromData(String data) 
 {
 tempUser = data.split(",");
 return new User(tempUser[0], int(tempUser[1]), int(tempUser[2]));
 }
 
 Object createNewUser(String name, int rank, int preferredColorIndex) 
 {
 return new User(name, rank, preferredColorIndex);
 }*/

char[] alphabet = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

String[] newUserFromString(String data) {
  String[] splitData = data.split(",");
  return splitData;
}

//User Object Variables
String[] tempUser;
User[] userList = new User[6];
Button[] userButtons = new Button[6];
String[] userListStrings = {"", "", "", "", "", ""};

//*************************************************************************Game Variables
class Paddle
{
  float speed = 1;
  int direction;
  float xpos;
  float ypos;
  int colorIndex = 1;
  int newColor;

  Paddle(int colorIndex, float speed, float xpos, float ypos)
  {
    this.speed = speed;
    this.xpos = xpos;
    this.ypos = ypos;
    this.colorIndex = colorIndex;
  }

  void setSpeed(float newSpeed) {
    this.speed = newSpeed;
  }
  void setColor(int colorIndex) {
    this.colorIndex = colorIndex;
  }

  int getColor() {
    return this.colorIndex;
  }

  void show(float xpos, float ypos) {
    switch(colorIndex) {
    case 1:
      newColor = 255;
      break;
    case 2:
      newColor = #FF0000;
      break;
    case 3:
      newColor = #0700FF;
      break;
    case 4:
      newColor = #B600FF;
      break;
    case 5:
      newColor = #1BFF08;
      break;
    case 666: //used for abilities
      newColor = 0;
      break;
    }
    fill(newColor);
    noStroke();
    rect(xpos, ypos, height/36, height/8);
    this.ypos = ypos;
  }

  void display(int direction) {
    noStroke();
    switch(colorIndex) {
    case 1:
      newColor = 255;
      break;
    case 2:
      newColor = #FF0000;
      break;
    case 3:
      newColor = #0700FF;
      break;
    case 4:
      newColor = #B600FF;
      break;
    case 5:
      newColor = #1BFF08;
      break;
    case 666: //used for abilities
      newColor = 0;
      break;
    }
    switch(direction) {
    case 2:
      fill(newColor);
      rectMode(CENTER);
      rect(xpos, ypos, height/36, height/8);
      break;

    case 0:
      if (ypos - height/16 > height/20) {
        ypos -= speed*height/250;
      }
      fill(newColor);
      rectMode(CENTER);
      rect(xpos, ypos, height/36, height/8);
      break;

    case 1:
      if (ypos + height/16 < height - height/20) {
        ypos += speed*height/250;
      }
      fill(newColor);
      rectMode(CENTER);
      rect(xpos, ypos, height/36, height/8);
      break;
    }
  }

  float getxPos() {
    return xpos;
  }
  float getyPos() {
    return ypos;
  }
}

class Ball
{
  float speed = 1;
  int direction = int(random(1, 4));
  float xpos = width/2;
  float ypos = height/2;
  int col = 1;

  Ball(float speed)
  {
    this.speed = speed;
  }
  void setSpeed(float newSpeed) {
    this.speed = newSpeed;
  }

  void setColor(int col) {
    this.col = col;
  }

  void show(int col) {
    switch(col) {
    case 1:
      col = 255;
      break;
    case 2:
      col = #0063FF;
      break;
    }

    noStroke();
    fill(col);
    xpos = width/2;
    ypos = height/2;
    rect(width/2, height/2, height/60, height/60);
    direction = int(random(1, 4));
  }

  void hide() {
    noStroke();
    fill(255);
    xpos = width/2;
    ypos = height/2;
    rect(-400, -400, 1, 1);
    direction = int(random(1, 4));
  }

  int display() {
    switch(col) {
    case 1:
      col = 255;
      break;
    case 2:
      col = #0063FF;
      break;
    }
    fill(col);
    switch(direction) {
    case 1:
      noStroke();
      rect(xpos, ypos, height/60, height/60);
      xpos += speed*width/400;
      ypos -= speed*width/400;
      break;

      case(2):
      noStroke();
      rect(xpos, ypos, height/60, height/60);
      xpos -= speed*width/400;
      ypos -= speed*width/400;
      break;

      case(3):
      noStroke();
      rect(xpos, ypos, height/60, height/60);
      xpos -= speed*width/400;
      ypos += speed*width/400;
      break;

      case(4):
      rect(xpos, ypos, height/60, height/60);
      xpos += speed*width/400;
      ypos += speed*width/400;
      break;
    }
    if (ypos <= height/20 + 5 && direction == 2) { //hit top from left
      direction = 3;
      return 0;
    }
    if (ypos <= height/20 + 5 && direction == 1) { //hit top from right
      direction = 4;
      return 0;
    }
    if (ypos + height/100 >= height - height/20 && direction == 3) { //hit bottom from left
      direction = 2;
      return 0;
    }
    if (ypos + height/100 >= height - height/20 && direction == 4) { //hit bottom from right
      direction = 1;
      return 0;
    }
    if (xpos <= paddle1.getxPos() + height/60 && ypos >= paddle1.getyPos() - height/16 && ypos <= paddle1.getyPos() + height/16 && direction == 2) { //hit left going up
      direction = 1;
      return 1;
    }
    if (xpos <= paddle1.getxPos() + height/60 && ypos >= paddle1.getyPos() - height/16 && ypos <= paddle1.getyPos() + height/16  && direction == 3) { //hit left going down
      direction = 4;
      return 1;
    }
    if (xpos + height/100 >= paddle2.getxPos() - height/120 && ypos >= paddle2.getyPos() - height/16 && ypos <= paddle2.getyPos() + height/16 && direction == 1) { //hit right going up
      direction = 2;
      return 2;
    }
    if (xpos + height/100 >= paddle2.getxPos() - height/120 && ypos >= paddle2.getyPos() - height/16 && ypos <= paddle2.getyPos() + height/16 && direction == 4) { //hit hit right going down
      direction = 3;
      return 2;
    }    
    if (xpos <= 0 && direction == 2) { //hit left going up
      return 3;
    }
    if (xpos <= 0 && direction == 3) { //hit left going down
      return 3;
    }
    if (xpos + height/100 >= width && direction == 1) { //hit right going up
      return 4;
    }
    if (xpos + height/100 >= width && direction == 4) { //hit hit right going down
      return 4;
    } else {
      return 0;
    }
  }
}

Paddle paddle1;
Paddle paddle2;
Ball ball;

int paddle1TempColor;
int paddle2TempColor;
int paddle1Charge;
int paddle2Charge;
int player1Lives;
int player2Lives;
int ballValues;

//**********************************************************************************Ability
void incrementCharge(int paddleCharge) {
  switch (paddleCharge) {
  case 0:
    break;
  case 1:
    if (paddle1Charge != 10) {
      paddle1Charge+= 5;
    }
    break;
  case 2:
    if (paddle2Charge != 10) {
      paddle2Charge+= 5;
    }
    break;
  }
}
int player1Ability;
int player2Ability;
int abilityTimer1 = 0;
int abilityTimer2 = 0;
//**********************************************************************************Setup
void setup() {
  //****WINDOW DIMENSIONS
  fullScreen();
  background(0);
  heightPixels = height;
  widthPixels = width;
  //****TEXT OBJECT DECLARATIONS
  infoFont = createFont("OCR A Extended", width/50, true);
  titleFont = createFont("Corbel Bold", width/6.5, true);
  //****CONTROLLER VALUES
  controller = new Serial(this, Serial.list()[0], 115200);
  controllerValues = new int[9];
  //****BUTTON OBJECTS
  startMatchButton = new Button(0, "START MATCH", width/2, 4*height/8);
  addUserButton = new Button(1, "ADD USER", width/2, 5*height/8);
  changeUserColorButton = new Button(2, "CHANGE COLOR", width/2, 6*height/8);
  howToPlayButton = new Button(3, "HOW TO PLAY", width/2, 7*height/8);
  selectUser1Button = new Button(4, "SELECT PLAYER 1", width/2, 3*height/8);
  selectUser2Button = new Button(5, "SELECT PLAYER 2", width/2, 4*height/8);
  playGameButton = new Button(6, "PLAY GAME", width/2, 6*height/8);
  //****GAME OBJECTS
  ball = new Ball(1);
  paddle1 = new Paddle(1, 2, width/36, height/2);
  paddle2 = new Paddle(1, 2, 35*width/36, height/2);
  for (int i = 0; i < particles.length; i++) {
    particles[i] = new Transition();
  }
  //****SOUND OBJECTS
  intro = new SoundFile(this, "intro.mp3");
  menu = new SoundFile(this, "menu.mp3");
  buttonClick = new SoundFile(this, "button.mp3");
  battle = new SoundFile(this, "battle.mp3");
  transitionSound = new SoundFile(this, "transition.mp3");
  win = new SoundFile(this, "win.mp3");
  ballOut = new SoundFile(this, "ballout.mp3");
  ability = new SoundFile(this, "ability.mp3");
  //****MENU BACKGROUND
  for (int i = 0; i < drops.length; i++) {
    drops[i] = new Drop();
  }
  //****GAME BACKGROUND
  for (int i = 0; i < stars.length; i++) {
    stars[i] = new Star();
  }
  startTime = millis();
}

//***********************************************************************************Draw
void draw() {

  //Load Users from Text File, if none, create one
  if (gameLoaded == false) {
    if (intro.isPlaying() != 1) {
      intro.play();
    }
    if (millis() - startTime < 7600) {
      textAlign(CENTER, CENTER);
      textFont(infoFont);
      fill(255);
      text("Loading User Data...", 4*width/5, 7*height/8);
    }
    if (millis() - startTime > 7600) {
      userData = loadStrings("userdata.txt");
      if (userData != null) {
        background(0);
        for (int i =  0; i < userData.length; i++) {
          String tempUserLine = userData[i];
          String[] tempUserData = newUserFromString(tempUserLine);
          try {
            userList[i] = new User(tempUserData[0], int(tempUserData[1]), int(tempUserData[2]));
          }
          catch (Exception e) {
            print("");
          }
        }
        printArray(userList);
        println("User Data loaded."); //Console Print for testing
        text("User Data loaded.", 4*width/5, 7*height/8);
        gameLoaded = true;
      } else {
        background(0);
        println("User Data not found. Creating new file."); //Console Print for testing
        text("User Data not found.", 4*width/5, 7*height/8);
        text("Creating new file.", 4*width/5, 7.25*height/8);
        userDatabase = createWriter("userdata.txt");
        userDatabase.flush();
        //userDatabase.close(); //I HAVE QUESTIONS ABOUT THIS
        userData = loadStrings("userdata.txt");
        gameLoaded = true;
      }
    }
  }

  //Intro Sequence to Game
  if (gameIntro == false && gameLoaded == true) {

    down = controllerValues[0];
    up = controllerValues[1];
    b = controllerValues[2];
    a = controllerValues[3];

    if (a == 1) {
      gameIntro = true;
      titleScreen = true;
      alpha = 255;
      intro.stop();
      valueFromController = 0;
      a = 0;
    }
    if (dotT < 800) {
      stroke(255);
      strokeWeight(5);
      translate(width/2, height/2);
      point(dotX(dotT), dotY(dotT));
      dotT += 4;
      alpha = 0;
    }
    if (alpha < 255 && dotT >= 800) {
      noStroke();
      fill(255, alpha);
      ellipse(width/2, height/2, 2*heightPixels/5, 2*heightPixels/5);
      alpha += 0.3;
    }
    if (alpha > 40 && alpha < 60) {
      background(255);
      fill(0);
      ellipse(width/2, height/2, 2*heightPixels/5, 2*heightPixels/5);
    }
    if (alpha > 50 && alpha < 70) {
      background(0);
      fill(255);
      ellipse(width/2, height/2, 2*heightPixels/5, 2*heightPixels/5);
    }
    if (alpha > 60 && alpha < 80) {
      background(255);
      fill(0);
      ellipse(width/2, height/2, 2*heightPixels/5, 2*heightPixels/5);
    }
    if (alpha > 100 && beginTitle != true) {
      alpha = 255;
      beginTitle = true;
      background(255);
      delay(2000);
    }
    if (beginTitle == true && scaleBall < 25) {
      background(0);
      fill(255);
      ellipse(3.5*width/8, 3*height/10, 3*width/scaleBall, 3*width/scaleBall);
      scaleBall += 0.2;
    }
    if (scaleBall > 25 && scaleBall < 35) {
      textFont(titleFont);
      textAlign(CENTER, CENTER);
      text('P', 2.5*width/8, 2.8*height/10);
      scaleBall ++;
    }
    if (scaleBall > 35 && scaleBall < 45) {
      textAlign(CENTER, CENTER);
      text('N', 4.55*width/8, 2.8*height/10);
      scaleBall ++;
    }
    if (scaleBall > 45 && scaleBall < 55) {
      textAlign(CENTER, CENTER);
      text('G', 5.5*width/8, 2.8*height/10);
      scaleBall ++;
    }
    if (scaleBall > 55) {
      gameIntro = true;
      titleScreen = true;
      valueFromController = 0;
      alpha = 255;
    }
  }

  //Title Screen (will have Start Match, Change User Color, Delete User, How To Play)
  if (titleScreen == true) {
    if (win.isPlaying() == 1) {
      win.stop();
    }
    if (menu.isPlaying() != 1) {
      menu.play();
      menu.amp(0.6);
    }

    down = controllerValues[0];
    up = controllerValues[1];
    b = controllerValues[2];
    a = controllerValues[3];

    background(0);
    for (int i = 0; i < drops.length; i++) {
      drops[i].fall();
      drops[i].show();
    }
    textAlign(CENTER);
    textFont(infoFont);
    text("©2018 Interaction Lab", width/2, 15*height/16);
    translate(0, -height/16);
    //Button Display
    startMatchButton.display();
    addUserButton.display();
    changeUserColorButton.display();
    howToPlayButton.display();

    //vvthese rectangles are over the buttons currently in beta to show they cannot be used
    rectMode(CENTER);
    noStroke();
    fill(255, 70);
    rect(width/2, 5*height/8, width/5, height/12);
    rect(width/2, 6*height/8, width/5, height/12);
    //^^these rectangles are over the buttons currently in beta to show they cannot be used

    if (alpha > 0) {
      noStroke();
      fill(0, alpha);
      rectMode(CORNER);
      rect(0, 0, width, height);
      alpha -= 3;
    } 
    fill(255);
    noStroke();
    ellipse(3.5*width/8, 3*height/10, 3*width/24.8, 3*width/24.8);
    textAlign(CENTER, CENTER);
    textFont(titleFont);
    text('P', 2.5*width/8, 2.8*height/10);
    text('N', 4.55*width/8, 2.8*height/10);
    text('G', 5.5*width/8, 2.8*height/10);

    //Test for arduino
    if (down == 1 && valueFromController != 0) {
      valueFromController --;
      buttonClick.play();
    }
    if (up == 1 && valueFromController != 3) {
      valueFromController ++;
      buttonClick.play();
    }
    //Button Selections to different screens
    if (valueFromController == startMatchButton.getButtonIndex() && a == 1) {
      startMatch = true;
      titleScreen = false;
      valueFromController = 4;
    }
    /*if (valueFromController == addUserButton.getButtonIndex() && a == 1) {
     createUser = true;
     titleScreen = false;
     valueFromController = 0;
     }*/
    /*if (valueFromController == changeUserColorButton.getButtonIndex() && a == 1) {
     changeUserColor = true;
     titleScreen = false;
     valueFromController = 0;
     }*/
    if (valueFromController == howToPlayButton.getButtonIndex() && a == 1) {
      howToPlay = true;
      titleScreen = false;
      valueFromController = 0;
    }
  }

  //************************************************************Start Match Options (SCREEN #4)
  if (startMatch == true) {

    down = controllerValues[0];
    up = controllerValues[1];
    b = controllerValues[2];
    a = controllerValues[3];

    //Test for arduino
    if (down == 1 && valueFromController != 4) {
      valueFromController --;
      buttonClick.play();
    }
    if (up == 1 && valueFromController != 6) {
      valueFromController ++;
      buttonClick.play();
    }
    if (b == 1) {
      startMatch = false;
      titleScreen = true;
      selectUser1Button.changeText("SELECT PLAYER 1");
      selectUser2Button.changeText("SELECT PLAYER 2");
      valueFromController = 0;
    }
    background(0);
    for (int i = 0; i < drops.length; i++) {
      drops[i].fall();
      drops[i].show();
    }
    //Select Users
    selectUser1Button.display();
    selectUser2Button.display();
    playGameButton.display();

    if (a == 1 && valueFromController == selectUser1Button.getButtonIndex()) {
      listUsers = true;
      startMatch = false;
      selectUserToAdd = true;
      player1Selected = true;
      player2Selected = false;
      a = 0;
      valueFromController = 7;
    }
    if (a == 1 && valueFromController == selectUser2Button.getButtonIndex()) {
      listUsers = true;
      startMatch = false;
      selectUserToAdd = true;
      player2Selected = true;
      player1Selected = false;
      a = 0;
      valueFromController = 7;
    }
    if (selectUser1Button.getButtonName() == "SELECT PLAYER 1" || selectUser2Button.getButtonName() == "SELECT PLAYER 2" ) {
      noStroke();
      fill(255, 70);
      rect(width/2, 6*height/8, width/5, height/12);
    }
    //(1st time) Return to Start Match Options showing one slot still open for another user
    //(2nd time) Return to Start Match Options unlocking Play button
    //Play Button (if two users are selected)
    if (selectUser1Button.getButtonName() != "SELECT PLAYER 1" && selectUser2Button.getButtonName() != "SELECT PLAYER 2" ) {
      //Starts Game
      if (a == 1 && valueFromController == playGameButton.getButtonIndex()) {
        transition = true;
        startMatch = false;
        a = 0;
        menu.stop();
        transitionCount = 0;
        alpha = 0;
      }
    }
  }

  //**********************************************List Users and allow player to select with the A button (SCREEN #5)
  if (listUsers == true && selectUserToAdd == true) {
    background(0);

    down = controllerValues[0];
    up = controllerValues[1];
    b = controllerValues[2];
    a = controllerValues[3];

    if (b == 1) {
      startMatch = true;
      listUsers = false;
      selectUserToAdd = false;
      player1Selected = false;
      player2Selected = false;
      valueFromController = 4;
    }
    //Test for arduino
    if (down == 1 && valueFromController > 7) {
      valueFromController --;
      buttonClick.play();
    }
    if (up == 1 && valueFromController < 12) {
      valueFromController ++;
      buttonClick.play();
    }
    for (int i = 0; i < drops.length; i++) {
      drops[i].fall();
      drops[i].show();
    }
    //Create User Button Objects
    for (int i = 0; i < userList.length; i++) {
      try {
        userButtons[i] = new Button(i+7, userList[i].getUsername(), width/4, (i+1)*height/7);
      } 
      catch(Exception e) {
        userButtons[i] = new Button(i+7, "NO USER", width/4, (i+1)*height/7);
      }
    }
    //Display User Button Objects
    for (int i = 0; i < userButtons.length; i++)
    {
      userButtons[i].display();
      try {
        text("WINS: " + userList[i].getRank(), 3*width/4, (i+1)*height/7 + height/49, width/5, height/12);
      }
      catch (Exception e) {
      }
    }
    if (userList[0] != null) {
      if (a == 1 && valueFromController == userButtons[0].getButtonIndex()) {
        if (player1Selected == true) {
          paddle1.setColor(userList[0].getPreferredColor());
          selectUser1Button.changeText(userList[0].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          startMatch = true;
          valueFromController = 4;
        }
        if (player2Selected == true) {
          paddle2.setColor(userList[0].getPreferredColor());
          selectUser2Button.changeText(userList[0].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          startMatch = true;
          valueFromController = 5;
        }
      }
    }
    if (userList[1] != null) {
      if (a == 1 && valueFromController == userButtons[1].getButtonIndex()) {
        if (player1Selected == true) {
          paddle1.setColor(userList[1].getPreferredColor());
          selectUser1Button.changeText(userList[1].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          startMatch = true;
          valueFromController = 4;
        }
        if (player2Selected == true) {
          paddle2.setColor(userList[1].getPreferredColor());
          selectUser2Button.changeText(userList[1].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          startMatch = true;
          valueFromController = 5;
        }
      }
    }
    if (userList[2] != null) {
      if (a == 1 && valueFromController == userButtons[2].getButtonIndex()) {
        if (player1Selected == true) {
          paddle1.setColor(userList[2].getPreferredColor());
          selectUser1Button.changeText(userList[2].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player1Selected = false;
          startMatch = true;
          valueFromController = 4;
        }
        if (player2Selected == true) {
          paddle2.setColor(userList[2].getPreferredColor());
          selectUser2Button.changeText(userList[2].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player2Selected = false;
          startMatch = true;
          valueFromController = 5;
        }
      }
    }
    if (userList[3] != null) {
      if (a == 1 && valueFromController == userButtons[3].getButtonIndex()) {
        if (player1Selected == true) {
          paddle1.setColor(userList[3].getPreferredColor());
          selectUser1Button.changeText(userList[3].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player1Selected = false;
          startMatch = true;
          valueFromController = 4;
        }
        if (player2Selected == true) {
          paddle2.setColor(userList[3].getPreferredColor());
          selectUser2Button.changeText(userList[3].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player2Selected = false;
          startMatch = true;
          valueFromController = 5;
        }
      }
    }
    if (userList[4] != null) {
      if (a == 1 && valueFromController == userButtons[4].getButtonIndex()) {
        if (player1Selected == true) {
          paddle1.setColor(userList[4].getPreferredColor());
          selectUser1Button.changeText(userList[4].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player1Selected = false;
          startMatch = true;
          valueFromController = 4;
        }
        if (player2Selected == true) {
          paddle2.setColor(userList[4].getPreferredColor());
          selectUser2Button.changeText(userList[4].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player2Selected = false;
          startMatch = true;
          valueFromController = 5;
        }
      }
    }
    if (userList[5] != null) {
      if (a == 1 && valueFromController == userButtons[5].getButtonIndex()) {
        if (player1Selected == true) {
          paddle1.setColor(userList[5].getPreferredColor());
          selectUser1Button.changeText(userList[5].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player1Selected = false;
          startMatch = true;
          valueFromController = 4;
        }
        if (player2Selected == true) {
          paddle2.setColor(userList[5].getPreferredColor());
          selectUser2Button.changeText(userList[5].getUsername());
          listUsers = false;
          selectUserToAdd = false;
          player2Selected = false;
          startMatch = true;
          valueFromController = 5;
        }
      }
    }
  }


  //*********************************************************************************Add User
  if (createUser == true) {
    //allow for arcade style username adding) (SCREEN #6)

    if (chooseColor == true && firstTimeAdd == true) {
      //Show different paddle colors, example of paddle,
      //and allow user to select with controller (SCREEN #7)
      //INITIALIZE NEW USER OBJECT AND SAVE TO TEXT FILE
      //RETURN TO SELECT USERS
    }
  }

  //***********************************************************************Change User Color
  if (changeUserColor == true) {
    //Create User Button Objects
    for (int i = 0; i < userList.length; i++) {
      if (userList[i].getUsername() != null) {
        userButtons[i] = new Button(i+6, userList[i].getUsername(), width/4, i*height/8);
      } else {
        userButtons[i] = new Button(i+6, "No User", width/4, i*height/8);
      }
    }
    //Display User Button Objects
    for (int i = 0; i < userButtons.length; i++)
    {
      userButtons[i].display();
    }


    //List Users and allow player to select User
    if (listUsers == true && selectUserToColor == true) {
    }

    if (chooseColor == true && firstTimeAdd != true) {
      //Copy User attributes (username and rank)
      //Delete User, bring to a clone of Color Screen in Add users
      //SAVE USERS
      //Return to Main Menu
    }
  }

  //********************************************************************************Delete User
  if (deleteUser == true) {
    //List Users and allow player to select User
    if (listUsers == true && selectUserToDelete == true) {
      //"are you sure?" let player cycle through yes and no
      //if yes,
      //Delete user from text data, and SAVE TEXT
      //Return to Main Menu
      //if no, 
      //return to Main Menu
    }
  }

  //********************************************************************************How To Play
  if (howToPlay == true) {

    down = controllerValues[0];
    up = controllerValues[1];
    b = controllerValues[2];
    a = controllerValues[3];

    if (b == 1) {
      howToPlay = false;
      titleScreen = true;
      valueFromController = 3;
    }
    background(0);
    for (int i = 0; i < drops.length; i++) {
      drops[i].fall();
      drops[i].show();
    }
    //Bring a small menu with text
    textAlign(CENTER, CENTER);
    textFont(titleFont);
    text("HOW TO PLAY", width/2, 2*height/10);
    textFont(infoFont);
    text("Go to 'START MATCH' and select users!", width/2, 4*height/10, width - width/10, height/12);
    text("Once you have selected two players, press 'PLAY GAME'", width/2, 5*height/10, width - width/10, height/12);
    text("To move the paddle, use the sensors to move up and down.", width/2, 6*height/10, width - width/10, height/12);
    text("Press the ability button to use your ability.", width/2, 7*height/10, width - width/10, height/12);
    text("Most importantly, use the B button to go back to the menu.", width/2, 8*height/10, width - width/10, height/12);
    //prompt player to press B button again to return to main menu
  }

  //**************************************************************************************PLAY
  if (transition == true) {
    //Paddle Charge initialize at 0 in this block instead of Play block to avoid accidental re-assignments to 0
    paddle1Charge = 0;
    paddle2Charge = 0;
    player1Lives = 3;
    player2Lives = 3;
    //Initialize gamestart
    gameOver = false;

    if (transitionCount >= 0 && transitionCount <= 100) {
      if (transitionSound.isPlaying() != 1) {
        transitionSound.play();
        transitionSound.amp(0.4);
      }
      for (int i = 0; i < particles.length; i++) {
        particles[i].fall();
        particles[i].show();
      }
      fill(255, alpha);
      noStroke();
      rectMode(CORNER);
      rect(0, 0, width, height);
      alpha += 2.3;
      transitionCount ++;
    } 
    if (transitionCount == 100) {
      delay(1000);
    }
    if (transitionCount > 100 && transitionCount <= 160) {
      background(0);
      for (int i = 0; i < stars.length; i++) {
        stars[i].show();
        stars[i].update();
      }
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      stroke(255, 170);
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);
      strokeWeight(1);
      //Print paddles(with color) and ball in initial spots
      //Prints players' profiles
      //Count Down (no one can move & ball doesnt move)
      paddle1.display(2);
      paddle2.display(2);
      ball.show(1);
      fill(255, alpha);
      rectMode(CORNER);
      rect(0, 0, width, height);
      alpha -= 4.5;
      transitionCount ++;
      if (battle.isPlaying() != 1) {
        battle.play();
        battle.amp(0.7);
      }
    }
    if (transitionCount > 160 && transitionCount <= 220) {
      background(0);
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      //Bars with names and lives
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      stroke(255, 170);
      //Court Lines
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);
      strokeWeight(1);
      for (int i = 0; i < stars.length; i++) {
        stars[i].show();
        stars[i].update();
      }
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      stroke(255, 170);
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);
      strokeWeight(1);
      paddle1.display(2);
      paddle2.display(2);
      ball.show(1);
      textFont(titleFont);
      textAlign(CENTER);
      textFont(titleFont);
      text("3", width/2, height/2);
      print('3');
      transitionCount++;
    }
    if (transitionCount > 220 && transitionCount <= 260) {
      background(0);
      for (int i = 0; i < stars.length; i++) {
        stars[i].show();
        stars[i].update();
      }
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      stroke(255, 170);
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);
      strokeWeight(1);
      paddle1.display(2);
      paddle2.display(2);
      ball.show(1);
      textFont(titleFont);
      textAlign(CENTER);
      text("2", width/2, height/2);
      print('2');
      transitionCount++;
    }
    if (transitionCount > 260 && transitionCount <= 300) {
      background(0);
      for (int i = 0; i < stars.length; i++) {
        stars[i].show();
        stars[i].update();
      }
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      stroke(255, 170);
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);
      strokeWeight(1);
      paddle1.display(2);
      paddle2.display(2);
      ball.show(1);
      textFont(titleFont);
      textAlign(CENTER);
      text("1", width/2, height/2);
      print('1');
      transitionCount++;
    }
    if (transitionCount > 300 && transitionCount <= 330) {
      background(0);
      for (int i = 0; i < stars.length; i++) {
        stars[i].show();
        stars[i].update();
      }
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      stroke(255, 170);
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);
      strokeWeight(1);
      paddle1.display(2);
      paddle2.display(2);
      ball.show(1);
      textFont(titleFont);
      textAlign(CENTER);
      text("GO!", width/2, height/2);
      print('g');
      transitionCount++;
    }
    if (transitionCount > 330) {
      playGame = true;
      transition = false;
    }
  }

  //*******************************************************************************GAME START
  if (playGame == true) {
    if (transitionSound.isPlaying() == 1) {
      transitionSound.stop();
    }
    if (gameOver != true) {
      background(0);
      stroke(255, 170);
      line(width/2, height/20, width/2, 2.375*height/20);
      line(width/2, 3.5625*height/20, width/2, 4.75*height/20);
      line(width/2, 5.9375*height/20, width/2, 7.125*height/20);
      line(width/2, 8.3125*height/20, width/2, 9.5*height/20);
      line(width/2, 10.6875*height/20, width/2, 11.875*height/20);
      line(width/2, 13.0625*height/20, width/2, 14.25*height/20);
      line(width/2, 15.4375*height/20, width/2, 16.625*height/20);
      line(width/2, 17.8125*height/20, width/2, 19*height/20);

      for (int i = 0; i < stars.length; i++) {
        stars[i].show();
        stars[i].update();
      }
      player1Values = controllerValues[6];
      player2Values = controllerValues[7];
      player1Ability = controllerValues[4];
      player2Ability = controllerValues[5];
      //Ball starts with Bouncy" code, random direction but,
      //changes direction only by hitting top and bottom, and paddles
      //triggers a switch when it collides with walls of the screen
      //Paddles can freely move, based on the info that distance sensors will be sending,
      //distance sensors will read either 1, or -1, the corresponding directions up, stop, and down
      paddle1.display(player1Values);
      paddle2.display(player2Values);
      //since ball.display actually returns values, 1 and 2 values are used to increment paddle charge
      ballValues = ball.display();
      incrementCharge(ballValues);

      //with each paddle collision, players will build up an "ability charge"
      //about 10 hits for ability
      //ability will be saved and not increase when full
      //ability will vary depending on paddles color
      //Checks if the paddle is fully charged
      if (paddle1Charge == 10 && player1Ability == 1) {
        abilityTimer1 = 0;
        paddle1Charge = 0;
        ability1Used = true;
      }
      //Checks the types of abilities the paddle can perform based on color
      /*
       -Ball Speed Increase ^
       -Paddle Speed Increase
       -Paddle distance Change
       -Paddle color change
       */
      if (ability1Used == true) {
        if (ability.isPlaying() != 1) {
          ability.play();
          ability.amp(0.4);
        }
        switch(paddle1.getColor()) {
        case 1:
          //White Ability
          if (abilityTimer1 <= 200) {
            ball.setSpeed(2);
            ball.setColor(2);
            battle.rate(3);
            spark1 = 0;
            abilityTimer1++;
          }
          if (abilityTimer1 > 200) {
            ball.setSpeed(1);
            ball.setColor(1);
            battle.rate(1);
            abilityTimer1 = 0;
            paddle1Charge = 0;
            ability.stop();
            ability1Used = false;
          }
          break;

        case 2:
          //Red Ability
          if (abilityTimer1 <= 200) {
            paddle1.setSpeed(3);
            battle.rate(3);
            spark1 = 0;
            abilityTimer1++;
          }
          if (abilityTimer1 > 200) {
            paddle1.setSpeed(2);
            battle.rate(1);
            abilityTimer1 = 0;
            paddle1Charge = 0;
            ability.stop();
            ability1Used = false;
          }
          break;

        case 3:
          //Blue Ability
          if (abilityTimer1 <= 200) {
            ball.setSpeed(0.25);
            ball.setColor(2);
            battle.rate(0.5);
            spark1 = 0;
            abilityTimer1++;
          }
          if (abilityTimer1 > 200) {
            ball.setSpeed(1);
            ball.setColor(1);
            battle.rate(1);
            abilityTimer1 = 0;
            paddle1Charge = 0;
            ability.stop();
            ability1Used = false;
          }
          break;

        case 4:
          //Purple Ability
          if (paddle2.getColor() != 666) {
            paddle2TempColor = paddle2.getColor();
          }
          if (abilityTimer1 <= 100) {
            paddle2.setColor(666);
            battle.rate(1);
            spark1 = 0;
            abilityTimer1++;
          }
          if (abilityTimer1 > 100) {
            paddle2.setColor(paddle2TempColor);
            battle.rate(1);
            abilityTimer1 = 0;
            paddle1Charge = 0;
            ability.stop();
            ability1Used = false;
          }
          break;

        case 5:
          //Green Ability
          if (abilityTimer1 <= 200) {
            paddle2.setSpeed(1);
            battle.rate(0.5);
            spark1 = 0;
            abilityTimer1++;
          }
          if (abilityTimer1 > 200) {
            paddle2.setSpeed(2);
            battle.rate(1);
            abilityTimer1 = 0;
            paddle1Charge = 0;
            ability.stop();
            ability1Used = false;
          }
          break;

        case 666: //if the user uses an ability while corrupted
          spark1 = 0;
          paddle1Charge = 0;
          ability1Used = false;
          ability.stop();
          break;
        }
      }

      if (paddle2Charge == 10 && player2Ability == 1) {
        paddle2Charge = 0;
        abilityTimer2 = 0;
        ability2Used = true;
      }  

      if (ability2Used == true) {
        if (ability.isPlaying() != 1) {
          ability.play();
          ability.amp(0.4);
        }
        switch(paddle2.getColor()) {
        case 1:
          //White Ability
          if (abilityTimer2 <= 200) {
            ball.setSpeed(2);
            ball.setColor(2);
            battle.rate(3);
            spark2 = 0;
            abilityTimer2++;
          }
          if (abilityTimer2 > 200) {
            ball.setSpeed(1);
            ball.setColor(1);
            battle.rate(1);
            abilityTimer2 = 0;
            paddle2Charge = 0;
            ability.stop();
            ability2Used = false;
          }
          break;

        case 2:
          //Red Ability
          if (abilityTimer2 <= 200) {
            paddle2.setSpeed(3);
            battle.rate(3);
            spark2 = 0;
            abilityTimer2++;
          }
          if (abilityTimer2 > 200) {
            paddle2.setSpeed(2);
            battle.rate(1);
            abilityTimer2 = 0;
            paddle2Charge = 0;
            ability.stop();
            ability2Used = false;
          }
          break;

        case 3:
          //Blue Ability
          if (abilityTimer2 <= 200) {
            ball.setSpeed(0.25);
            ball.setColor(2);
            battle.rate(0.5);
            spark2 = 0;
            abilityTimer2++;
          }
          if (abilityTimer2 > 200) {
            ball.setSpeed(1);
            ball.setColor(1);
            battle.rate(1);
            abilityTimer2 = 0;
            paddle2Charge = 0;
            ability.stop();
            ability2Used = false;
          }
          break;

        case 4:
          //Purple Ability
          if (paddle1.getColor() != 666) {
            paddle1TempColor = paddle1.getColor();
          }
          if (abilityTimer2 <= 100) {
            paddle1.setColor(666);
            battle.rate(1);
            spark2 = 0;
            abilityTimer2++;
          }
          if (abilityTimer2 > 100) {
            paddle1.setColor(paddle1TempColor);
            battle.rate(1);
            abilityTimer2 = 0;
            paddle2Charge = 0;
            ability.stop();
            ability2Used = false;
          }
          break;

        case 5:
          //Green Ability
          if (abilityTimer2 <= 200) {
            paddle1.setSpeed(1);
            battle.rate(0.5);
            spark2 = 0;
            abilityTimer2++;
          }
          if (abilityTimer2 > 200) {
            paddle1.setSpeed(2);
            battle.rate(1);
            abilityTimer2 = 0;
            paddle2Charge = 0;
            ability.stop();
            ability2Used = false;
          }
          break;

        case 666: //if the user uses an ability while corrupted
          spark2 = 0;
          paddle2Charge = 0;
          ability.stop();
          ability2Used = false;
          break;
        }
      }

      //each player will have 3 lives
      //when ball hits players wall, 
      //they lose a life, ball starts at the beginning of match,
      //with lives changed accordingly
      //since ball.display also returns a 3 or 4 if the outskirts of the map are hit, this will be used
      //to affect players' lives
      if (ballValues == 3 && player1Lives != 0) {
        player1Lives --;
        ball.hide();
        ballOut.play();
        /*for (int i = 0; i < 3000; i++) {
         translate(random(width/5, width/2), random(height/5, width/2));
         }*/
        delay(2000);
        ballOut.stop();
      } else if (ballValues == 4 && player2Lives != 0) {
        player2Lives --;
        ball.hide();
        ballOut.play();
        /*for (int i = 0; i < 3000; i++) {
         translate(random(width/5, width/2), random(height/5, width/2));
         }*/
        delay(2000);
        ballOut.stop();
      }

      //Print Users (GUI)
      rectMode(CORNER);
      strokeWeight(5);
      stroke(255);
      fill(0);
      rect(0, 19*height/20, width, 1*height/20);
      rect(0, 0, width, 1*height/20);
      strokeWeight(1);
      textAlign(CENTER);
      textFont(infoFont);
      fill(255);
      text(selectUser1Button.getButtonName(), width/40, 0.1*height/20, width/10, height/20);
      text(selectUser2Button.getButtonName(), width/40, 19.1*height/20, width/10, height/20);

      //Print Graphics for Ability and Lives
      abilityBar1(paddle1Charge, spark1);
      abilityBar2(paddle2Charge, spark2);
      printP1Lives(player1Lives, paddle1.getColor());
      printP2Lives(player2Lives, paddle2.getColor());

      //Print Ability Names
      if (paddle1Charge == 10) {
        switch(paddle1.getColor()) {
        case 1:
          textAlign(CORNER);
          fill(255);
          text("BALLBOOST", 3.3*width/4, 3*height/80);
          break;

        case 2:
          textAlign(CORNER);
          fill(255);
          text("PADDLEBOOST", 3.3*width/4, 3*height/80);
          break;

        case 3:
          textAlign(CORNER);
          fill(255);
          text("CHILL OUT", 3.3*width/4, 3*height/80);
          break;

        case 4:
          textAlign(CORNER);
          fill(255);
          text("CORRUPT", 3.3*width/4, 3*height/80);
          break;

        case 5:
          textAlign(CORNER);
          fill(255);
          text("SLOWPADDLE", 3.3*width/4, 3*height/80);
          break;

        case 666:
          textAlign(CORNER);
          fill(255);
          text("CORRUPTED", 3.3*width/4, 3*height/80);
          break;
        }
      }

      if (paddle2Charge == 10) {
        switch(paddle2.getColor()) {
        case 1:
          textAlign(CORNER);
          fill(255);
          text("BALLBOOST", 3.3*width/4, 79*height/80);
          break;

        case 2:
          textAlign(CORNER);
          fill(255);
          text("PADDLEBOOST", 3.3*width/4, 79*height/80);
          break;

        case 3:
          textAlign(CORNER);
          fill(255);
          text("CHILL OUT", 3.3*width/4, 79*height/80);
          break;

        case 4:
          textAlign(CORNER);
          fill(255);
          text("CORRUPT", 3.3*width/4, 79*height/80);
          break;

        case 5:
          textAlign(CORNER);
          fill(255);
          text("SLOWPADDLE", 3.3*width/4, 79*height/80);
          break;

        case 666:
          textAlign(CORNER);
          fill(255);
          text("CORRUPTED", 3.3*width/4, 79*height/80);
          break;
        }
      }


      //when one has 0 lives,
      if (player1Lives == 0) {
        ball.hide();
        endGameTimer = 0;
        gameOver = true;
      }
      if (player2Lives == 0) {
        ball.hide();
        endGameTimer = 0;
        gameOver = true;
      }
    }


    //*****************************************************************************GAME OVER
    if (gameOver == true) {
      battle.stop();
      if (win.isPlaying() != 1) {
        win.play();
        win.amp(0.7);
      }
      if (endGameTimer <= 500) {
        background(0);
        for (int i = 0; i < stars.length; i++) {
          stars[i].show();
          stars[i].update();
        }
        rectMode(CORNER);
        strokeWeight(5);
        stroke(255);
        fill(0);
        rect(0, 19*height/20, width, 1*height/20);
        rect(0, 0, width, 1*height/20);
        textAlign(CENTER);
        textFont(infoFont);
        fill(255);
        text(selectUser1Button.getButtonName(), width/40, 0.1*height/20, width/10, height/20);
        text(selectUser2Button.getButtonName(), width/40, 19.1*height/20, width/10, height/20);
        strokeWeight(1);
        //"Username wins!"
        abilityBar1(paddle1Charge, spark1);
        abilityBar2(paddle2Charge, spark2);
        printP1Lives(player1Lives, paddle1.getColor());
        printP2Lives(player2Lives, paddle2.getColor());
        paddle1.show(width/36, height/2);
        paddle2.show(34*width/36, height/2);

        //Print Ability Names
        if (paddle1Charge == 10) {
          switch(paddle1.getColor()) {
          case 1:
            textAlign(CORNER);
            fill(255);
            text("BALLBOOST", 3.3*width/4, 3*height/80);
            break;

          case 2:
            textAlign(CORNER);
            fill(255);
            text("PADDLEBOOST", 3.3*width/4, 3*height/80);
            break;

          case 3:
            textAlign(CORNER);
            fill(255);
            text("CHILL OUT", 3.3*width/4, 3*height/80);
            break;

          case 4:
            textAlign(CORNER);
            fill(255);
            text("CORRUPT", 3.3*width/4, 3*height/80);
            break;

          case 5:
            textAlign(CORNER);
            fill(255);
            text("SLOWPADDLE", 3.3*width/4, 3*height/80);
            break;

          case 666:
            textAlign(CORNER);
            fill(255);
            text("CORRUPTED", 3.3*width/4, 3*height/80);
            break;
          }
        }

        if (paddle2Charge == 10) {
          switch(paddle2.getColor()) {
          case 1:
            textAlign(CORNER);
            fill(255);
            text("BALLBOOST", 3.3*width/4, 79*height/80);
            break;

          case 2:
            textAlign(CORNER);
            fill(255);
            text("PADDLEBOOST", 3.3*width/4, 79*height/80);
            break;

          case 3:
            textAlign(CORNER);
            fill(255);
            text("CHILL OUT", 3.3*width/4, 79*height/80);
            break;

          case 4:
            textAlign(CORNER);
            fill(255);
            text("CORRUPT", 3.3*width/4, 79*height/80);
            break;

          case 5:
            textAlign(CORNER);
            fill(255);
            text("SLOWPADDLE", 3.3*width/4, 79*height/80);
            break;

          case 666:
            textAlign(CORNER);
            fill(255);
            text("CORRUPTED", 3.3*width/4, 79*height/80);
            break;
          }
        }

        if (player1Lives == 0) {
          textAlign(CENTER);
          textFont(titleFont);
          fill(255);
          text(selectUser2Button.getButtonName() + "  WINS!", width/2, height/2);
        }
        if (player2Lives == 0) {
          textAlign(CENTER);
          textFont(titleFont);
          fill(255);
          text(selectUser1Button.getButtonName() + "  WINS!", width/2, height/2);
          //User's amount of wins goes up
        }
        endGameTimer += 1;
      }

      if (endGameTimer >  500) {
        if (player1Lives == 0) {
          //User's amount of wins goes up
          for (int i = 0; i < userList.length; i++) {
            try {
              if (selectUser2Button.getButtonName() == userList[i].getUsername()) {
                userList[i].addRank();
              }
            }
            catch (Exception e) {
            }
          }
        }
        if (player2Lives == 0) {
          for (int i = 0; i < userList.length; i++) {
            try {
              if (selectUser1Button.getButtonName() == userList[i].getUsername()) {
                userList[i].addRank();
              }
            }
            catch (Exception e) {
            }
          }
        }
        //SAVES USER STATS
        userDatabase = createWriter("userdata.txt");
        for (int i = 0; i < userList.length; i++) {
          try {
            userListStrings[i] = userList[i].getUsername() + ',' + str(userList[i].getRank()) + ',' + str(userList[i].getPreferredColor());
          }
          catch (Exception e) {
            userListStrings[i] = "";
          }
        }
        saveStrings("userdata.txt", userListStrings);

        //Fix any glitches during game
        paddle1.setSpeed(2);
        paddle2.setSpeed(2);
        ball.setSpeed(1);
        ball.setColor(1);
        battle.rate(1);
        abilityTimer1 = 0;
        abilityTimer2 = 0;
        paddle1Charge = 0;
        paddle2Charge = 0;

        //Returns to Main Menu
        paddle1.show(width/36, height/2);
        paddle2.show(34*width/36, height/2);
        delay(1000);
        win.stop();
        playGame = false;
        titleScreen = true;
        valueFromController = 0;
        endGameTimer = 0;
      }
    }
  }
}

void serialEvent(Serial controller) {
  String myString = controller.readStringUntil(10);
  if (myString != null) {
    //println(myString);
    String[] serialInArray = split(trim(myString), ",");
    if (serialInArray.length == controllerValues.length) {
      for (int i = 0; i < serialInArray.length; i++) {
        controllerValues[i] = int(serialInArray[i]);
        //print(controllerValues[i]);
      }
    }
  }
}

//ARDUINO CODE
/*
int pins[10];
int i1;
int i2;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  for (int i = 2; i < 8; i++) {
    pinMode(i, INPUT);
  }
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  for (int i = 2; i < 8; i++) {
    if (i != 6 || i != 7) {
      if (pins[i] == 1) {
        Serial.print(0);
        Serial.print(',');
        pins[i] = digitalRead(i);
      }
      else {
        pins[i] = digitalRead(i);
        Serial.print(pins[i]);
        Serial.print(',');
      }
    }
  }
  //Distance Sensors
  i1 = analogRead(A0);
  i2 = analogRead(A1);
  if (i1 > 320) {
    Serial.print(1);
    Serial.print(',');
  } else if (i1 < 320) {
    Serial.print(0);
    Serial.print(',');
  }
  if (i2 > 320) {
    Serial.print(1);
    Serial.print(',');
  } else if (i2 < 320) {
    Serial.print(0);
    Serial.print(',');
  }


  Serial.println(0);
  delay(10);
}
*/

The Single Shot: Lillian Korinek

I carried around my camera for a couple of days–  I shot a men climbing in and out of a window of a construction site in puxi, I even shot a loan bike sitting in the snow restless and alone (for some reason the personification on inanimate labor made me sad). But, it wasn’t until I woke up one early morning that I realized exactly the labor I wanted to document: the act of applying make-up. Millions of women do it everyday; some feel it is a labor of love (?) some feel it is a labor of necessity (?)

Video Games: “The Chesuit Mission”, Nicholas Sanchez’s final project

I began this process with ideation and research. Inspired by the 2016 movie “The Greasy Strangler”, I initially considered creating a video game where the main character went around strangling NPCs. This seemed too dark, so instead I decided that converting NPCs to religion would be a more appropriate theme. Based off of blatant evangelical Protestant conversion practices, I created a game where the main character, a Crustian Chesuit Missionary, sets out to convert all non believers to his cause. However, a game where one just goes around and converts NPCs sans challengers is not interesting, so I decided to create two enemies to impede upon user success. The first, the “Cat-Holic” missionary, would convert non believer NPCs or those you  had converted into a “Cat-holic” convert. The “Militant non believer” bad guy would turn all converted NPC’s back into their non believer status.

Once I had a mythology going, I went about bringing my characters to life in Adobe Fuse.

Here were the initial designs for “Non Believer NPCs”:

screen-shot-2016-11-06-at-4-25-40-pm

screen-shot-2016-11-07-at-1-05-25-pm

 

 

 

screen-shot-2016-11-06-at-5-31-19-pm

 

 

 

 

screen-shot-2016-11-06-at-4-52-19-pm

 

 

 

 

I endeavored to make this NPC look sickly and miserable, which lends itself to the idea that only through conversion might these characters find peace.

After I created this model, I used this form to make the “Crustian convert” and “Cat-holic convert” models:

screen-shot-2016-11-06-at-5-19-22-pmscreen-shot-2016-11-06-at-5-22-36-pm

screen-shot-2016-11-06-at-5-26-58-pm

 

 

 

 

 

 

screen-shot-2016-11-06-at-5-24-24-pm

 

 

screen-shot-2016-11-06-at-5-25-49-pm

 

 

 

 

 

 

 

 

 

These models were physically happier than the non believer. They shared many similarities, save clothing color and eyes.

To design the Cat-holic convert, I channeled the cultural perception of a crazy cat lady. Here is the design I ended up with.

screen-shot-2016-11-07-at-1-04-07-pm

The final baddy would be the “Militant Non Believer”. His character would be an obese figure with sparse facial hair and a fedora.

screen-shot-2016-11-06-at-10-45-37-pm

screen-shot-2016-11-06-at-11-01-42-pm

screen-shot-2016-11-07-at-1-03-03-pm
After initially presenting these characters to the class, some feedback I received indicated that the game was too heavily masculine, and that the addition of female NPCs would help the gender discrepancy. So I added these models as well as designed the main character.

Here are the female NPC non Believers

screen-shot-2016-11-10-at-4-32-51-pmscreen-shot-2016-11-10-at-4-32-41-pm

 

 

 

 

 

Here are the models for the main character:

screen-shot-2016-11-15-at-6-24-18-pm

screen-shot-2016-11-15-at-6-24-35-pm

 

 

 

 

 

 

 

screen-shot-2016-11-15-at-6-37-57-pm             screen-shot-2016-11-15-at-6-38-07-pm

Once this was done, I attempted to give these characters skeletons and animate them to create FBXs for Unity. Unfortunately, the number of vertices made each character impossible to boolean together, causing me to use low poly characters in the games final instead of these models.

screen-shot-2016-11-23-at-10-54-34-amscreen-shot-2016-11-28-at-8-46-53-pm

 

 

 

 

 

 

Then it became time to build the scene aspects. I decided that the game would take place in an urban setting, like a city street. I decided to emulate Los Angeles’ skid row, which is notorious for its homeless population. To emulate this, I designed buildings and other street assets for the game.

screen-shot-2016-11-16-at-8-28-41-pm screen-shot-2016-11-16-at-9-02-03-pm screen-shot-2016-11-17-at-3-33-19-pm screen-shot-2016-11-17-at-3-45-00-pm screen-shot-2016-11-22-at-10-37-47-pm screen-shot-2016-11-22-at-10-37-49-pm screen-shot-2016-11-23-at-1-01-03-am

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Here you can see some of the street aspects I made, like buildings, trash cans, and street lights. The next step was to export these objects from Blender into Unity, and create a scene. Once all the finished assets were in Unity, I created a “model” block that incorporated each of these models. This would serve as the building block for my scenes, as each “street” would be comprised of any amount of these prefabs. Below you may observe this basic street object.screen-shot-2016-11-26-at-7-13-29-pm

From here I had to give these elements textures and create a model “block” which would essentially make up each levels scene. 
screen-shot-2016-11-28-at-6-28-57-pm

 

 

 

 

 

After using various scripts provided in class, I set about making a prototype that would illustrate the functions of the game. To access this build, click HERE.

The task of building this game was a precarious one, entailing many hours of scripting, alteration, and amendment. I had to make some cuts, like the primary actions of the two enemies. However, I did create an opening animation and tutorial scene to better situate the gamer within the context of plot and controls. To see this animation, view the video below

chessuit-missionary-opening3

At the beginning of the semester, designing a video game seemed little more than a simple final project, typical of what I might accomplish in other classes. Now that all is said and done, I can say with certainty that I was very, very wrong. Setting out to make a video game was perhaps one of the most challenging endeavors I had set on throughout my collegiate experience, as this project required skills in several softwares, hours of production, and coding. And while I can say that what I submitted as my final was an unpolished, perhaps Alpha, version of a game, I can say with certainty that the experience I gained while building this project and the final product were well worth the effort. For links to the final (and an improved one I made after the fact) click here.

Bruce’s Final Game Changes — Tire-Ring

Based on the prototype and user feedback, I made a few changes.

First, changed how I organize and stitch the tracks.

snipaste20161212_165626

Now there is a reference point to stitch to the end.

snipaste20161212_165345

Tracks are prefabs loaded in the scene under an empty object “track_sets”. They will be randomly picked and copied to extend the track.

snipaste20161212_165457

snipaste20161212_170054

Lights on the track for speed reference.

Scores are calculated by accumulating the speed, literally, the faster and farther the player goes, the higher the score is.

When the tire fall on the platform for 3 seconds, the game restarts automatically.

Download Link:

https://drive.google.com/open?id=0B-RqhxWjt3c6ZG41YzZSckc3c1k

FINAL GAME PROJECT | Zeerak Fayiz

Link to Final Build: https://drive.google.com/open?id=0B7vPRTPpGgt9Y3FTSG5LUzZTSTg

As many people said, my game was very ambitious and very complex. There is a lot going on, and the player has to figure out stuff. I too felt the same, as I started preparing for my final build. The amount of problems I ran into was insane! For my final build, I had to make a lot of changes to improve my game. I started off by changing the “Evil Minions” in the game, to make it more in line with the whole theme and environment.

I also edited the way the text was displayed during conversations. I also placed “control instructions” into one of the conversations, and purposely put the main character next to the NPC, thinking that the player would be curious and approach the NPC, starting the conversation.

I finally added the third key to the game, as well as an end scene. As soon as the player goes into the dragon castle after collecting the 3 keys, a third scene would load, congratulating the player for breaking the spell of eternal winter.

I also got the fighting to work between the minion and the main player, however, there is a glitch in the game because of which sometimes either the minion doesn’t die, or the player falls through the terrain once they collide with the enemy (I was thinking of using this to my advantage, and call this “game over”).

I improved the inside of the castle, by reducing the light inside, and adding torches. The player can now easily navigate throughout the whole area without getting stuck. Turns out, the “snow dome” was making the player stuck in places. I still have no idea why that is…

I also added Queen Isabel to the scene, to give the player motivation and more context once they collect one of the keys.

While editing the scene, I realised that there was a part of the castle that did not have a staircase or anything for the player to get to the top of the castle. So, I added panel like thingys on which the player can jump (using the “Space” key).

I completely removed the use of the mouse during gameplay, and made the game fully keyboard controlled, as during our user testing session, a lot of players asked me to do so, as they found it difficult to use the mouse and keyboard at the same time (plus my mouse script was not the best).

All in all, I am proud that I managed to achieve more than just my top 3 priorities (as listed in last documentation) for my final build. The only thing left now to add is animation to the NPC villagers and giving them random paths to move in, and adding some more sound effects.

Making this game has been a wonderful and very learning experience, and I can’t wait to make more of such games!

Pictures below:

454353

45345435435

7777777777

888

999

0000

98

66

8475

85734895

111

capture121

 

 

 

 

Saphya: Piggy Party Final Game

Previously…

The Evolution of “Piggy Party”

Updates:

New Minigame 4 (Hot Pigtato)!

After struggling with the physics in Minigame 2 and 3,  I’ve decided to create another minigame with easier mechanics as I work on troubleshooting the others. I took the disk from Minigame 2 and separated it into four objects in Blender before exporting the .fbx in Unity and making animations there. I was having too much trouble with exporting the Blender animations so I decided to forego that and try out Unity animations. I thought that animating objects in Unity was much easier than in Blender. With all the animations now done, I made an array with every piece of the disk inside, so that every five seconds, up to three pieces are randomly triggered. The objective of this minigame is to outlast the timer, and avoid the other player so you don’t get pushed off the platform.

screenshot-304

Minigame 1 – Pig Grows Larger!

With every coin, the pig is scaled up by (0.025f, 0.025f, 0.025f). Whichever pig reaches (0.7,0.7,0.7) first, wins the round.

screenshot-309

Main Menu and Modes!

Instead of jumping right into the main map, players now have the option of playing story mode (main map and randomized mini games) or minigame mode where players can select whichever minigame they like best.

screenshot-303

Instructions!

To help players know which pig they are playing as, and the controls for the game.

screenshot-307

Marjorie Wang’s Final Video Game

Throughout the course of the semester, I have been developing an exploratory video game featuring a cute astronaut’s last mission on his three-mission long expedition to far-out star systems. Upon entry, the player, as the endearing astronaut, is placed into the very homey spaceship, with information on the last two missions, a message from Earth, and instructions for the latest mission, all framed by some calming elevator music.
The Build.
screen-shot-2016-12-11-at-11-38-36-pm
The spaceship.
screen-shot-2016-12-11-at-11-38-54-pm
Enter the pod to begin.

Once the player finishes exploring their role, they may enter the Sputnik-like pod to begin their mission. The player is then whisked into space, and is able to explore the various worlds in Star System 49452.screen-shot-2016-12-11-at-11-39-14-pm
A few of the planets.

Upon collision onto the diamond planet (the silver cube), the player is transported to the surface of the planet, which features colorful gems, amongst which diamond-shaped Earth objects are hidden.
screen-shot-2016-12-11-at-11-39-52-pm
Diamond-shaped lucky Chinese papers.

screen-shot-2016-12-11-at-11-40-32-pm
Road signs.

screen-shot-2016-12-11-at-11-41-12-pm
Kites.

Another planet is Soupworld, an otherworldly dance party fueled by pop music, twirling single-celled organisms, and Andy Warhol’s artwork. The player passes through five rooms, with bouncing pop art Campell soup cans and organisms.
screen-shot-2016-12-12-at-12-32-08-am
The planet.

screen-shot-2016-12-12-at-12-32-25-am
Wow! Inhabited planet!

screen-shot-2016-12-12-at-12-32-39-am
Money soup campell warhol money.

The next planet is the volcano planet. Here, I wanted to play with scale, by shrinking , thus rendering the astronaut’s perspective enormous in comparison to the scale of objects we know on Earth.
screen-shot-2016-12-12-at-12-37-19-am
Tiny volcano and tiny Sputnik.

Another planet to explore is the vaporwave planet. Upon entry into Wechat, the player is placed into a QR code maze and once the center of the maze is reached, the player is dropped far above the maze and falls through pills to Vaporwave imagery, to reach my video game interpretation of the website, “What does your horse dream mean

screen-shot-2016-12-12-at-10-57-46-am
The QR code maze.

screen-shot-2016-12-12-at-10-58-09-am
Pills.

screen-shot-2016-12-12-at-10-58-14-am
Palm trees: vaporwave imagery.

screen-shot-2016-12-12-at-10-58-19-am
Columns and pedestals.

screen-shot-2016-12-12-at-10-58-29-am
Pyramids in gradient colors.

screen-shot-2016-12-12-at-10-58-38-am
Finally to fall onto what we’ve all been waiting for: What does your horse dream mean?

Another planet is the supermarket planet, similar to Campbell planet in the focus on consumerism on Earth. There is a fruit floor, a meat floor and a hole in the ground to exit.
screen-shot-2016-12-12-at-1-08-58-pm

screen-shot-2016-12-12-at-1-10-11-pm
First floor fruit.

screen-shot-2016-12-12-at-1-10-11-pm
Bottom floor meat.

Overall, I am quite satisfied with the final product of my first video game. As a scripting-not-even-beginner, I was able to focus on the aspect of making a game that I enjoy the most, the visuals. Although many times, I remembered the reading that told us good graphics does not excuse a bad game, I hope I was able to overcome this obstacle to make something that people enjoy playing. I do wish I was able to make more planets, to enhance the level of detail of the objects in each planet–perhaps to create more levels in the supermarket.

I originally ideated the premise of my game because it seemed most interesting and feasible to be adapted in virtual reality.
Here is one prototype of the VR version of the game.

Crash Test Final Update – Xiaoyang Sun

Level Design:

Lv 01

1

First level is a demonstration of basic controls and mechanics. It uses simple animation and audio trigger.

Lv 02

2

I made new animations for second level and a trigger to let go of the black cube to smash the car.

Lv 03

3

Those red bars are doors. Each door is controlled by one button. I modified the trigger script to make the buttons work. And also with a click the button will now change color. However, I intended to only change the color of the red cube, but the script does it oppositely. Probably because the script is getting the first material in the object, and for the buttons, their first material is the grey part. Script as below:

4

In game effect as below:

5

However, when animating the doors, I did it separately for each door. I bet there must be an easier way to do this.

Lv 04

6

For this level, I designed to make it like a small maze. But given the limitation of the size of the board, the way I could think of to increase the difficulty is to take out the lights.

In game effect as below:

7

I used spot light for the front lights, and point lights for area effect and lights in the back.

8

Therefore, the player is only able to see certain tiles in front of him/her. Thus there is higher probability that the player will step into the dead end. I also added the restart function so that the player could try again if they get stuck.

Script as below:

17

Also to trigger the entrance of the bulldozer, I used a series of red spot lights and animation trigger to give the bulldozer a dramatic entrance.

In game effect:

9

Lv 05:

10

Instead of destroying the car, I tried something different. I made this level an escape level. I used Nav Mesh to make the red spheres follow the player. At first I only baked the level base, the spheres are able to go across the fences. I changed the fences and doors into Nav Obsticles, then my problem was solved.

11

However, one of the spheres is behaving very weird. It could always go across the boarder of the fences and I have no choice but to change the Nav Agent into animation.

That is all of the level design right now.

GUI and Level Transition:

I fixed the title screen and now the title scene can finally load up properly.

12

I added transitions between levels using triggers and Unity’s built in level loading functions

13

Script below:14

At fist the transition was too fast. It jumps right into the transition scene as my car hits the collider. Then I searched online and got the instructions on how to delay the transition.

15

Right now I only have very simple transition scenes. I wish I would be able to add replays of he car crash in the transition scene.

Sound Effects:

I added in many new sound effects to spice up the game. Most of the audio sources are from YouTube.

16

 

Overall, if anything I want to change in the future, it is definitely going to be making this game a true tile-based movement game. Right now the control gets crazy sometimes and it is probably not really good for the players. Unless they find the movement of the car funny. But lacking a precise control might make some of the mechanics hard to work.

Link to the builds on Google Drive:

https://drive.google.com/drive/folders/0B1_qNo-UThrzSHpVXzJRZHhBdXM?usp=sharing

 

 

 

WenYao Tang Final: Survivor

So from the feed back, firstly, I adjusted the cross hair and the laser pointing problem.

crosshair

Then I added a gameover animation clip so that player knows he died.

gameover-clip

I also build a winning clip, together I animated them.

animation

Then I build the pause menu for the game

 

 

 

menu

Also, I added some punishment for player if they fall out of the map

punishment

Then I added the choice scene to impliment the original idea.

choice

Then I followed the feedback to apply different mat and size for monsters with different score. Here different scene have different parameters, so that the players’ choice do effect their game play.

new-mat

Then I build two more scene for the result of the choice player made so that they know what is the following game play will be.

 

result-2

result1

Then finally I adjusted the design, attatched sound to the monster, changed layout (the anchor point sometimes screwed up), fixed minor bugs and other stuff to make sure the game is good to go. It is really impressive to see myself building a game from 0. 1 semester is short, but still I learned a lot. Unity is pretty fun 🙂

Hope you guys will love my game:)

The attachment is the game you can try out:)

https://drive.google.com/drive/folders/0B7A3TTb5cZc0TzBqdlI2R3l2TDQ?usp=sharing

Response to “The Designer’s Notebook: Sorting Out the Genre Muddle” – Xiaoyang Sun

The Designer’s Notebook: Sorting Out the Genre Muddle” by Ernest Adams dives in the complicate and yet fast-developing world of video games. Ernest looks into different aspects of video games such as genre, setting, audience, theme and purpose.

 

Adams gives a clear break down of the genres of video games and introduced the concept of “super-genres”. A “super-genre” can be divide into sub-genres. By going into specific sub-genres, games are able to stand out in the mass video game market. However, looking at today’s games, the developers are going in the different direction: to create games that could mix as many genres in there as possible. Take The Elder Scroll: Skyrim” as an example. Generically, it is a 3D, open world, role play game. But more specifically in game, player could choose the way they want to play. They can be an archer (or a mage) and turn the combat into shooters, or they can pick up the sword and shield to get into some action. They may even choose the stealth path and avoid combat. Not to mention other games such as GTA V, Watchdogs, etc. Many games today are mixing as many genres into a fictional simulation of one (or multiple characters) character in a sandbox.

 

Also in the section talking about audience of the game, he mentioned that “games for girls” is a marketing term. It has nothing to do with gameplay”. However, these “marketing terms” do imply certain genres of games that people associate with girls (eg: dress-up game or dance games [no offense]). Same with “games for boys”, or even “games for men”. Even though they are marketing terms, they do give implications of game genres.

 

I also find the section about setting interesting. Adams stated that “A shooter is a shooter, whether it’s set in the Old West or on Mars or anyplace else. A player who enjoys shooters will probably enjoy one no matter where it’s set, if it’s well-made”. A counter-example would be the call of duty series. There is definitely sales difference and different ratings for their games with different settings. A player who likes call of duty under World War II setting may not necessarily have the same feeling towards “Infinite Warfare”, the newest one in space. Setting does play a huge role in game. Otherwise Call of Duty: Infinite Warfare wouldn’t suffer a huge crisis in the face of Battlefield 1.