Final Project – Dance Evolution/User Testing

Concept:

For my final project “Dance Evolution”, I decided to work on a “remake” of a famous Japanese video game called “Dance Revolution.” In this game, instead of being provided the music at the beginning, the user has to press on the tiles in order to generate and construct the music itself track by track. For each round, the user is shown an arrow pointing either to the left or to the right and they have to press on the respective tile in a timely manner, otherwise they lose. Them pressing on the tiles will start slowly “unlocking new tracks,” allowing them to construct the final song.

Implementation:

 

Arduino:

My Arduino board consisted of 3 force sensors. These would then trigger the work of p5js. However, an issue I faced for some time was that when the sensor was activated, Arduino would register multiple high values of the sensor, which was inconvenient specifically for my project as it would set off a chain of undesirable events. Therefore, when working on my Arduino board and code, I had to make sure I debounced the signal properly so that it only registered the activation only once when the sensor is pressed.

p5.js:

Initially, I thought that the p5.js implementation of the project would be straightforward. However, I encountered a variety of different issues that made me change my approach to making this game. Firstly, I was unable to properly play the sounds of my tracks when the sensors were pressed.  It was very difficult to come up with an algorithm in which the activation of a sensor would lead to the playing of a track in a way that matches the other tracks (that may already be played) rhythmically. Therefore, I decided to play all the tracks in the setup and simply unmute each track when the sensor is triggered.

My p5.js code would take in the values of the sensor, or more specifically “signs” from the Arduino that the sensor was pressed and reached its maximum value, and would use that in order to generate new rounds of the game. My biggest obstacle throughout this process was creating an algorithm that would a) randomly pick between the two different images of arrows, b) make the user go from one round to the other, c) have the pictures be timed so that if the sensor is activated late, the user loses, etc. However, mainly through the usage of the “millis()” function, I was able to tackle these issues.

Code:

p5.js:

let bg;

//variables for all the musical tracks

let bass;

let hat;

let kick;

let snare;

let synth;

let strings;

let vox1;

let vox2;

let now; //variable that trackes the time every time the user presses on a button 

let gameStartTime; //tracks the beginning of each round

let sensorValue;

let middleSensorVal;//value of the sensors that p5js receives from Arduino

let gameState = "start"; // Can be 'start', 'playing', 'end'

let threshold = 5000; //the value for the first arrow that appears

let num = 0; //the value that activates the different cases

let arrowImage = []; //an array that holds the values of the images of the arrows

let randomIndex; //selects a random image from an array 

function preload() {
  vox1 = loadSound("vox_1.mp3");

  kick = loadSound("kick.mp3");

  vox2 = loadSound("vox_2.mp3");

  snare = loadSound("snare.mp3");

  bass = loadSound("hat.mp3");

  strings = loadSound("strings.mp3");

  synth = loadSound("synth.mp3");

  hat = loadSound("hat.mp3");

  bg = loadImage("background_image.png"); 
  
  arrowImage.push(loadImage("rightArrow.png"));
  arrowImage.push(loadImage("leftArrow.png")); //pushing the images into the array 

  bruno = loadFont("BrunoAceSC-Regular.ttf"); //loading the font of the game
}

function setup() {
  createCanvas(windowWidth, windowHeight);
  textAlign(CENTER);
  imageMode(CENTER);

  //playing all the tracks during setup and muting each track

  vox1.setVolume(0);
  vox1.play();
  vox1.loop();

  vox2.play();
  vox2.setVolume(0);
  vox2.loop();

  strings.play();
  strings.setVolume(0);
  strings.loop();

  snare.play();
  snare.setVolume(0);
  snare.loop();

  synth.play();
  synth.setVolume(0);
  synth.loop();

  kick.play();
  kick.setVolume(0);
  kick.loop();

  bass.play();
  bass.setVolume(0);
  bass.loop();

  hat.play();
  hat.setVolume(0);
  hat.loop();
}

function draw() {
  background(220);
  image(bg, width / 2, height / 2, width, height);
  
  //assigning different functions to different states of the game

  if (gameState == "start") {
    drawMainPage();
  } else if (gameState == "instructions") {
    drawInstructions();
  } else if (gameState == "playing") {
    drawGame();
  } else if (gameState == "win") {
    drawWinScreen();
  } else if (gameState == "loss") {
    drawLossScreen();
  } 
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

function drawMainPage() {
  textSize(70);
  fill("rgb(255,0,163)");
  stroke(255);
  strokeWeight(5);
  textWrap(WORD);
  textFont(bruno);
  text("Dance Evolution", width / 2, height / 5, width / 13);

  textSize(18);
  fill("white");
  stroke(0);
  strokeWeight(4);
  textFont(bruno);
  text("Press the Space Bar for the Instructions", width / 2, height / 1.2);
}

//setting up the serial connection

function keyPressed() {
  if (key == " ") {
    setUpSerial();
    gameState = "instructions";
  }
}

function drawInstructions() {
  textSize(60);
  fill("rgb(255,0,163)");
  stroke(255);
  strokeWeight(5);
  textWrap(WORD);
  textFont(bruno);
  text("Instructions", width / 2, height / 5);
  
  textWrap(WORD);
  textSize(16);
  stroke(0);
  strokeWeight(3);
  fill(255);
  textFont(bruno);
  text(
    "Once you start the game, you will see an arrow. Wherever the arrow points, that's the tile you should click on. Once you click on the tile, you will hear a track playing. Below the picture of the arrow, you will see the number of seconds you are given for each round. If you don't press the tile in time, you LOSE! If you manage to press on all the arrows on time and play all the tracks, you WIN!",
    0,
    height/2.5,
    width
  );
  
  textSize(18);
  fill("white");
  stroke(0);
  strokeWeight(4);
  textFont(bruno);
  text("Step on the Tile in the Middle to Play!", width / 2, height / 1.2);

  if (middleSensorVal == 1023) {
    gameState = "playing";
    restartRound(); //begins the game when the button is pressed
  }
}

function drawGame() {
  textSize(60);
  fill("rgb(255,0,163)");
  stroke(255);
  strokeWeight(5);
  textWrap(WORD);
  textFont(bruno);
  text("DANCE!", width / 2, height / 6.5);
  
  //tracking to see if the time that passed since the start of the round is less than the time the threshold

  if (millisInGame() < threshold && num < 8) {
    image(arrowImage[randomIndex], width / 2, height / 2, width/2, height/2);

    fill(255);
    strokeWeight(0);
    text(
      round(millisInGame() / 1000) + "/" + round(threshold / 1000) + " s",
      width / 2,
      height / 1.15
    );
  }
  
  //assigning the conditions for loss
  
  if (millisInGame() > threshold && num < 8) {
    gameState = "loss";
  }

  if (sensorValue === 1023 && num < 9) {
    num++;
    console.log(num);
    restartRound();
    threshold = threshold * 0.92;
    console.log(threshold);
    flag = true;
  }

  if (num == 8) {
    drawWinScreen();
  }
  
  switch (num) {
    case 0:
      break;
    case 1:
      vox1.setVolume(0.2);
      break;
    case 2:
      vox2.setVolume(0.2);
      break;
    case 3:
      kick.setVolume(0.2);
      break;
    case 4:
      bass.setVolume(0.2);
      break;
    case 5:
      snare.setVolume(0.2);
      break;
    case 6:
      hat.setVolume(0.2);
      break;
    case 7:
      synth.setVolume(0.2);
      break;
    case 8:
      strings.setVolume(0.2);
      break;
  }
}

function drawWinScreen() {
  background(220);
  image(bg, width / 2, height / 2, width, height);

  textSize(40);
  fill("rgb(255,0,163)");
  stroke(255);
  strokeWeight(5);
  textWrap(WORD);
  textFont(bruno);
  text("CONGRATULATIONS", width / 2, height / 5);
  
  textSize(18);
  fill("white");
  stroke(0);
  strokeWeight(4);
  textFont(bruno);
  text("Step on the tile in the middle to RESTART!", width / 2, height / 1.2);
  
  //restarting the game when the middle sensor is played

  if (middleSensorVal == 1023) {
    gameState = "instructions";
    vox1.setVolume(0);
    vox2.setVolume(0);
    strings.setVolume(0);
    snare.setVolume(0);
    synth.setVolume(0);
    kick.setVolume(0);
    bass.setVolume(0);
    hat.setVolume(0);
    num = 0;
    threshold = 5000;
  }
}

//tracking the start time of each round and generating an index to then randomly generate an image from the array 

function restartRound() {
  now = millis();
  gameStartTime = now;

  randomIndex = floor(random(arrowImage.length));
}

//tracking the difference between the current time and the moment when the game started

function millisInGame() {
  return millis() - gameStartTime;
}

function drawLossScreen() {
  textSize(60);
  fill("rgb(255,0,163)");
  stroke(255);
  strokeWeight(5);
  textWrap(WORD);
  textFont(bruno);
  text("LOSS", width / 2, height / 5);

  if (middleSensorVal == 1023) {
    gameState = "instructions";
    vox1.setVolume(0);
    vox2.setVolume(0);
    strings.setVolume(0);
    snare.setVolume(0);
    synth.setVolume(0);
    kick.setVolume(0);
    bass.setVolume(0);
    hat.setVolume(0);
    num = 0;
    threshold = 5000;
  }
  
  textSize(18);
  fill("white");
  stroke(0);
  strokeWeight(4);
  textFont(bruno);
  text("Step on the tile in the middle to RESTART!", width / 2, height / 1.2);
}

//receiving the information from the Arduino

function readSerial(data) {
  if (data != null) {
    let fromArduino = split(trim(data), ",");

    if (fromArduino.length == 2) {
      
      middleSensorVal = int(fromArduino[0]);
      sensorValue = int(fromArduino[1]);

    }
  }
}

function keyTyped() {
  if (key === 'f') {
    toggleFullscreen();
  }
}
function toggleFullscreen() {
  let fs = fullscreen(); 
  fullscreen(!fs); 
}

 

Arduino

const int leftPSensor = A0;
const int rightPSensor = A1;
const int middleSensor = A2; 

int lastSensorStateLeft = 0;
int lastSensorStateMiddle = 0;

int threshold = 1022;

bool flag = false;

int rightPressureVal;
int leftPressureVal;
int middleSensorVal;

void setup() {

  pinMode(leftPSensor, INPUT);
  pinMode(rightPSensor, INPUT);
  pinMode(middleSensor, INPUT);
  Serial.begin(4800);
}

void loop() {

  leftPressureVal = analogRead(leftPSensor);
  rightPressureVal = analogRead(rightPSensor);
  middleSensorVal = analogRead(middleSensor);


  if (leftPressureVal < threshold && rightPressureVal < threshold && middleSensorVal < threshold) {
    flag = true;
  } 

  if (flag == true && (leftPressureVal == 1023 || rightPressureVal == 1023)) {
      lastSensorStateLeft = 1023;
      flag = false;
    delay(300);
  } else {
    lastSensorStateLeft = 0;
  }

  if (flag == true && middleSensorVal == 1023) {
      lastSensorStateMiddle = 1023;
      flag = false;
      delay(300);
  } else {
    lastSensorStateMiddle = 0;
  }

  Serial.print(lastSensorStateMiddle);
  Serial.print(", ");
  Serial.println(lastSensorStateLeft);
}

Communication:

The communication between Arduino and p5.js proved to be a difficulty. As mentioned earlier, I tackled the issue of multiple registrations of the activation of the sender by debouncing it and ensuring that the value of the sensor is sent to p5js only once. However, when that was happening, despite p5.js recognizing the value, it would simply ignore it, even though it was clearly instructed to carry out an operation with the value. After some time, I realized that this issue could be resolved by decreasing the baud rate from 9600 to 4800 on both p5js and Arduino, which would allow p5js to recognize the one, small “1023” value that gets lost in a fast stream of values that are being received from Arduino. This was very helpful as it fixed the issue and ensured the smooth operation of the game.

Future improvements:

With this project, I am proud that it ultimately became what I envisioned, albeit with some limitations. I am proud of the algorithm that I used for flipping through rounds using the sensor and playing the different tracks themselves.

In the future I want to make sure there is more randomness to the process in terms of the different tracks that are played because as of now, the tracks are played in the same order. I also want to add different levels of difficulty where the user can choose to make the time given for their step on the tiles shorter. Finally, I want to improve the p5.js – Arduino communication in order to make sure that the user does not have to press on the tiles a few times for the value to be registered, which is an issue I observe currently.

Video:

 

User Testing:

I conducted user testing on one of my friends, whom I did not have explain the Instructions to. According to him, the instructions were clear. Despite that, he still struggled at times with clicking on the tiles as they would take a few tries for the value to be received by p5.js. All in all, however, he claimed that the game is fairly easy to understand.

 

Final Project Proposal – Revision Week 12

Concept

For my finally project, I was inspired by a classic Japanese video game called “Dance Revolution.” In this game, the user hears a song and has to tap on the right tiles of the platform that is under them in order to win the game: the tiles on which the person has to tap on appear faster and the game becomes harder over time. However, to put my own spin on the project, I decided to reverse the idea, and create “Dance Evolution.” In this game, the user will not be given a prior song but rather a set of tiles that they have to press on, similar to the original, and construct the song themselves.

picture taken from https://www.reddit.com/r/DanceDanceRevolution/comments/85guhf/my_self_made_ddr_pad_gallery_and_howto_in_comments/

The tiles will be modeled after the iconic “Dance Revolution” tiles.

Implementation:

The user will construct the song with the help of a set of successive arrows that they have to tap on, which in turn represent a certain instrument. After tapping, these instruments will be layered and will start turning into an actual song. The trick is that the user has to tap on the arrows/tiles in a timely manner, as the time slot for a successful tap will shrink over time. The user wins if they are able to tap on all tiles correctly and create the song that consists of all instruments: the beat, the bass, the chords, the melody, the pad, etc. The user loses if they do not tap on the tile on time, thereby ruining the structure of the song.

The instruments will most likely be generated using p5.js, in order to add an element of randomness and unpredictability so that the melodies and the beats heard in one round of the game will be different in another round. The user will also have the possibility of changing the key of the song by using a distance sensor, allowing them to hear the song in different renditions of their own volition.

Arduino input:

There would be nine tiles in total and five of them would have a function. Each tile would be connected to a pressure sensor that would then trigger some sort of operation. The tiles on the sides pointing up, down, right, and left would be used for the game itself, while the tile in the middle would perform general functions such as restarting the game, going from one window to another.

Meanwhile, p5js would light up the tiles due to an LED connected to the tiles showing the user what tile to press on.

Final Project Proposal – Yerkebulan Imanbayev

Concept

For my finally project, I was inspired by a classic Japanese video game called “Dance Revolution.” In this game, the user hears a song and has to tap on the right tiles of the platform that is under them in order to win the game: the tiles on which the person has to tap on appear faster and the game becomes harder over time. However, to put my own spin on the project, I decided to reverse the idea, and create “Dance Evolution.” In this game, the user will not be given a prior song but rather a set of tiles that they have to press on, similar to the original, and construct the song themselves.

picture taken from https://www.reddit.com/r/DanceDanceRevolution/comments/85guhf/my_self_made_ddr_pad_gallery_and_howto_in_comments/

The tiles will be modeled after the iconic “Dance Revolution” tiles.

Implementation:

The user will construct the song with the help of a set of successive arrows that they have to tap on, which in turn represent a certain instrument. After tapping, these instruments will be layered and will start turning into an actual song. The trick is that the user has to tap on the arrows/tiles in a timely manner, as the time slot for a successful tap will shrink over time. The user wins if they are able to tap on all tiles correctly and create the song that consists of all instruments: the beat, the bass, the chords, the melody, the pad, etc. The user loses if they do not tap on the tile on time, thereby ruining the structure of the song.

The instruments will most likely be generated using p5.js, in order to add an element of randomness and unpredictability so that the melodies and the beats heard in one round of the game will be different in another round. The user will also have the possibility of changing the key of the song by using a distance sensor, allowing them to hear the song in different renditions of their own volition.

Week 11 – in class exercises – Sarthak and Yerk

Exercise 1

Scheme: 

Code:

let xVal = 0; //initializing the X value for the position 

function setup() {
  createCanvas(640, 480);
}

function draw() {
  background(230);
  if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    // draw an ellipse
    ellipse(xVal, height/2, 100, 50); //giving the ellipse the value of the x position initialized above

  }
}

function keyPressed() {
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }
}

function readSerial(data) {
  if (data != null) {
    xVal = map(data, 0, 500, 0, width); //mapping the values received from the photosensor to control the X position of the ellipse 
    console.log(data);
  }
}
const int pSensor = A0;

void setup() {
  pinMode(pSensor, INPUT);
  Serial.begin(9600);
}

void loop() {
  int val = analogRead(pSensor); //initializing the value received from the sensor 
  Serial.println(val); //sending the value of the sensor to p5js
}

Video:

 

Exercise 2

Scheme: 

Code:

//p5js code

let change = 0; //initializing the variable for the distance between two consecutive center points of the rectangle
let previousX; //initializing the variable for the X dimension of the previous position of the rectangle 
let previousY; //initializing the variable for the Y dimension of the previous position of the rectangle 

function setup() {
  createCanvas(640, 480);
  textSize(18);
  textAlign(CENTER);
  previousX = 0;
  previousY = 0;
}

function draw() {
  background('red');

  if (!serialActive) {
    fill('white');
    text("Press Space Bar to select Serial Port", width/2, height/2);
  } else {
    fill('white');
    rectMode(CENTER);
    rect(mouseX, mouseY, 200,200); //controlling the center of the rectangle with the mouse 
    fill('black');
    text("Move as fast as you can to control the brightness of the LED", width/2,20);
    getChange(); //calling the function that will track the distance between the two consecutive positions of the rectangle 
  }
  
}

//calculating the distance of two consecutive rectangle positions 
function getChange(){ 
  change = floor(sqrt(pow((mouseX - previousX),2) + pow((mouseY - previousY),2)));
  previousX = mouseX;
  previousY = mouseY;
}

function keyPressed() {
  if (key == " ") {
    setUpSerial();
  }
}

function readSerial(data) {
  if (data != null) {
    console.log(change);
    writeSerial(change); //sending the value of the distance two control the LED brightness 
  }
}
const int led = 9;

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

  while (Serial.available() <= 0) {
    Serial.println("0");
    delay(300);
  }
}

void loop() {
  while (Serial.available()) {
    int brightness = Serial.parseInt(); // read the incoming data as an integer
    analogWrite(led, brightness); // set the LED brightness based on incoming data
    Serial.println();
  }
}

Video:

Exercise 3

Scheme: 

Code:

//p5js code

let velocity;
let gravity;
let position;
let acceleration;
let wind;
let drag = 0.99;
let mass = 50;

let ard_wind = 1; //initializing the wind speed 
let bit;

function setup() {
  createCanvas(640, 360);
  position = createVector(width / 2, 0);
  velocity = createVector(0, 0);
  acceleration = createVector(0, 0);
  gravity = createVector(0, 0.5 * mass);
  wind = createVector(0, 0);
  bit = 0; //initializing the value for the LED
}

function draw() {
  background(255);

  if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    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; 
      bit = 1; //lighting up the LED upon collision with "the ground"
    } else {
      bit = 0; //turning off the LED when the ball is not touching "ground"
    }
  }
}

function applyForce(force) {
  // Newton's 2nd law: F = M * A
  // or A = F / M
  let f = p5.Vector.div(force, mass);
  acceleration.add(f);
}

function keyPressed() {
  if (keyCode == LEFT_ARROW) {
    wind.x = ard_wind * -1; //when left arrow is pressed, the velocity of the wind attains a negative value and the ball moves to the left 
  }
  if (keyCode == RIGHT_ARROW) {
    wind.x = ard_wind; //when the right arrow is pressed, the velocity of the wind attains a positive value and the ball moves to the right 
  }
  if (keyCode == DOWN_ARROW) {
    mass = random(15, 80);
    position.y = -mass;
    velocity.mult(0);
  }
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }
}

function readSerial(data) {
  if (data != null) {
    let sen = bit + "\n";
    writeSerial(sen); //sending the values to light up or turn off the LED
        
    ard_wind = map(data, 0, 300, 0, 10); // mapping the data received from arduino to a sensible range for the wind velocity 
    console.log(ard_wind);    
  }
}
const int led = 12;
const int photoSensor = A0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(photoSensor, INPUT);

  while (Serial.available() <= 0) {
    Serial.println(0);
    // delay(300);
  }
}

void loop() {
  while (Serial.available() > 0) {
    int bit = Serial.parseInt(); // read the incoming data as an integer
    digitalWrite(led, bit); // set the LED brightness based on incoming data

 //send the values of the photosensor to p5js
    int val = analogRead(photoSensor); 
    Serial.println(val);
  }
}

Video:

 

Home Work 10 – Sarthak and Yerk (AutoTune)

AutoTune

Concept:

For this project, we were inspired by AutoTune. AutoTune allows you to take a certain musical key and make sure all the notes are aligned within that key, thereby perfecting the sound.

Execution: 

For the circuit, we used a buzzer, three switches, and a distance sensor. Initially, we used the key of C major and the note C as our reference point. Having calculated the mathematic relationships that exist between notes in a major key, we assigned different intervals of distance to different notes for that key. For instance, if the user’s hand is 0-5 cm away from the sensor, the circuit will play a C note. If the hand is 5-10 cm away, the circuit will play a D note. This method does not let notes that do not belong in the C major key to be played, which perfects the sound of the board. Just like AutoTune.

When the yellow button is pressed, the key that is being played is transposed up a half step. So if the user is playing in a C major key, once the yellow button is pressed, the user will now play in D flat major. The green button executes the opposite effect – it transposes the key down a half step. If a user is playing in F major, upon pressing the button, they will play in E major.

Finally, if the blue button is pressed, the user will now play in the natural minor key, completely changing the mathematical relationships that underlie the notes. For instance, if the user was playing in the G major key, once they press the button, they will hear the G minor key. This process goes the other way around: if the button is pressed again, the user will go back to the major key.

Circuit: 

 

Code:

int note_c = 262;

const int beeperPin = 12;
const int trigPin = 7;
const int echoPin = 8;
const int yellowSwitch = A0;
const int greenSwitch = A2;
const int blueSwitch = A4;

const int division = 5;

int flag = 1;

// this is the number of notes in an octave
const int num = 8;

int all_notes[num];

int getDistance() {
  // this bit of code was taken from https://howtomechatronics.com/tutorials/arduino/ultrasonic-sensor-hc-sr04/

  // calculating the distance between the user and the sensor
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);

  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  int duration = pulseIn(echoPin, HIGH);
  int distance = duration * 0.034/2;

  Serial.print("Distance: ");

  return distance;
}

int getNote(int distance) {
  int index = distance / division;

  return all_notes[index];
}

void makeMajorKey() {
  // making an array of all the notes in an octave given in the major key.
  all_notes[0] = note_c;
  int n = 1;
  for (int i = 1; i < num; i++) {
    // the third and seventh note change is a half step.
    if ((n % 3 == 0 && n % 6 != 0) || n % 7 == 0){
      all_notes[i] = all_notes[i-1] * pow(2, 1.0/12.0);
    } else {
      all_notes[i] = all_notes[i-1] * pow(2, 1.0/6.0);
    }
    n++;
  }
}

void makeMinorKey() {
  // making an array of all the notes in an octave in the minor key.
  all_notes[0] = note_c;
  int n = 1;
  for (int i = 1; i < num; i++) {
    // the second and fifth note change is a half step.
    if ((n % 2 == 0 && n % 4 != 0 && n % 6 != 0 && n % 8 != 0) || n % 5 == 0){
      all_notes[i] = all_notes[i-1] * pow(2, 1.0/12.0);
    } else {
      all_notes[i] = all_notes[i-1] * pow(2, 1.0/6.0);
    }
    n++;
  }
}

void setup() {
  pinMode(beeperPin, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(yellowSwitch, INPUT);

  Serial.begin(9600);

  makeMajorKey();
}

void loop() {
  // PipeLine
  // get the distance of an object
  int distance = getDistance();
  if (distance <= division * num) {
    // create note for that distance
    int note_to_play = getNote(distance);

    // play the note
    tone(beeperPin, note_to_play);

    // switch to transpose up
    int yellow_state = digitalRead(yellowSwitch);

    // switch to transpose down
    int green_state = digitalRead(greenSwitch);

    // switch to toggle between major and natural minor key
    int blue_state = digitalRead(blueSwitch);

    if (yellow_state == HIGH) {
      // transposing the key of the instrument a half-step up, when the switch is clicked.
      note_c = note_c * pow(2, 1.0/12.0);
      makeMajorKey();
    }

    if (green_state == HIGH) {
      // transposing the key of the instrument a half-step down, when the switch is clicked.
      note_c = note_c / pow(2, 1.0/12.0);
      makeMajorKey();
    }

    // changes major key to natural minor key and vice versa.
    if (blue_state == HIGH) {
      if (flag == 1) {
        makeMinorKey();
        flag = 0;
      } else {
        makeMajorKey();
        flag = 1;
      }
    }
  }
}

 

Video:

Future Improvements: 

One of the issues with the current board is that the code may register the clicking of the button as multiple clicks, even if the user had pressed the button once. With the yellow and the green buttons, this leads to a higher or a lower transposition than expected. With the blue button, there are instances when it simply skips over the shift to the minor key because it registers one click as two. In the future, we want to work toward eliminating that inconvenience.

 

Week 9 – Yerkebulan Imanbayev

Concept:

For my digital sensors assignment, I used the sun and the moon as an inspiration. I used a yellow LED to represent the sun and a blue LED to represent the moon.

Implementation:

When the yellow button is pressed, the yellow LED – a.k.a. the Sun – lights up and when the blue button is pressed, the blue LED – a.k.a. the moon – lights up. When both buttons are pressed at the same time, they each blink and alternate for 1 second with an interval of 0.5 seconds, representing the cycle of the sun and the moon.

Circuit schematics: 

Video:

Code:

int yellowLED = 13; //labeling the digital output for the yellow LED
int blueLED = 9; //labeling the digital output for the blue LED

void setup() {
  pinMode(yellowLED, OUTPUT);
  pinMode(blueLED, OUTPUT);
  pinMode(A0, INPUT);
  pinMode(A2, INPUT);
}

void loop(){

  int switchPositionYellow = digitalRead(A0);
  int switchPositionBlue = digitalRead(A2);

  if (switchPositionYellow == HIGH) { //if the yellow button is pressed, the yellow LED is turned on
    digitalWrite(yellowLED, HIGH);
    digitalWrite(blueLED, LOW);
  }

  else if (switchPositionBlue == HIGH) { // if the blue button is pressed, the blue LED is turned on
    digitalWrite(yellowLED, LOW);
    digitalWrite(blueLED, HIGH);
  }

  else {
    digitalWrite(yellowLED, LOW); //if both buttons aren't pressed, the LEDs are turned off
    digitalWrite(blueLED, LOW);
  }

  if (switchPositionYellow == HIGH && switchPositionBlue == HIGH) { //if both buttons are pressed, 
                                                                    //both LEDS will blink and will alternate
    digitalWrite(yellowLED, HIGH); 
    delay(1000);                      
    digitalWrite(yellowLED, LOW);   
    delay(500);       

    digitalWrite(blueLED, HIGH);  
    delay(1000);                      
    digitalWrite(blueLED, LOW);   
    delay(500);       
  }
}

Future Improvements:

In the future, I want to uphold and develop the concept Moresby including an analog sensor that detects light. When the light shines, “the sun” – yellow LED – would turn on, and when the light does not shine, “the moon” – blue LED – would turn on.

Unusual Switch – Yerkebulan Imanbayev

Idea:

For my unusual switch, I was inspired by Grinch and his signature furrowed eyebrows. Specifically, I decided to create my circuit in a way that grimacing (or furrowing your brows) is equal to the action of turning over the switch.

Execution:

I decided to create a simple circuit with a resistor and an LED. I have a wire that is connected to the power source and the LED. The LED is connected to a resistor, which, in turn, is connected to a wire. This wire is connected to a strip of aluminum foil, which is taped to one of my brows. I connected another wire to the ground and then taped aluminum foil on it as well, connecting it to my other brow. Now, if I furrow my eyebrows, the aluminum brows connect, conducting the electricity and turning the light bulb. If I do not make a Grinch face, the wires are disconnected, which does not conduct any electricity. Below, I created a simple diagram of the circuit:

Video:

Midterm Project – Yerkebulan Imanbayev

Concept:

With this project, I decided to focus on the classic game of “Whack-A-Mole.” Initially, I was planning to recreate the game, but then after the realization that it will become more of an exercise than a project, I decided to change the concept. I thought of it more realistically and what a game like that might possibly entail – and one of the interpretations of it could be that it is animal abuse. Therefore, I decided to expand on that concept and use the game as a platform to share awareness about animal abuse. That’s why instead of “whacking” a mole, the user has to “whack” a politician who committed or contributed to animal abuse.

Game features:

When the user hits any key to be redirected to the “game” window, they can see the time and the score being displayed. There are two characters in front of them: the mole and the politician. There is only one way to win in this game: to whack the politician 30 times in the span of 20 seconds. However, there are two different ways to lose in this game: the user can accidentally click on the mole – in which case they lose automatically – or they do not manage to whack the politician 30 times in the span of 20 minutes.

Generally, I attempted to make the game design appealing by creating the background image using DALL-E 2. The colors of the buttons and the text were picked so as to ensure legibility and conveyance of the sense of fun, quirky arcade games that we all know and love. The game is also designed to ensure that all buttons have a sound attached to them, including the background sound that is constantly playing unless the user is on the “win” or “loss” window.

Issues:

There were multiple issues I faced when I first started working on the project. Due to a large number of lines in the code, it was very hard for me to keep track of my variables and the functions. That is why my first step in tackling all of those issues was to give my variables a sensible name and making sure to comment on confusing parts of my code.

The next issue I faced was positioning my characters in the ellipses. I did not know how to do that because the function that contained the coordinates for my ellipses was separate from the class that contained the coordinates for my characters. That is when one of my friends suggested using a double array. After the coordinates of the ellipses were placed in the double array, they were called in the class as the coordinates for the characters.

  //creating an array to hold the coordinates of all the ellipses to refer to it later on
  arrayEllipses = [
    [95, 225],
    [95, 325],
    [95, 425],
    [235, 225],
    [235, 325],
    [235, 425],
    [375, 225],
    [375, 325],
    [375, 425],
  ];
}
//pulling out random elements from my array
   this.randomNumberPolitician = int(random(0, 9));
   this.randomNumberMole = int(random(0, 9));
   
   //check if the integer is the same; if so, choose a different hole for the mole
   while (this.randomNumberPolitician == this.randomNumberMole) {
     hoverMole = false;
     this.randomNumberPolitician = int(random(0, 9));
     this.randomNumberMole = int(random(0, 9));
   }

   //changing the position of the politician if the image is clicked
   if (hoverPolitician && mouseIsPressed) {
     this.politicianX = arrayEllipses[this.randomNumberPolitician][0];
     this.politicianY = arrayEllipses[this.randomNumberPolitician][1];
     this.moleX = arrayEllipses[this.randomNumberMole][0];
     this.moleY = arrayEllipses[this.randomNumberMole][1];
     clicks++;
     buttonSound.play();
   }

One of the elements in the code embedded above was my solution for the next issue I faced: because the coordinates assigned to the characters came from the same array, they were inevitably going to be equal at some point, leading to the mole and the politician appearing in the same ellipse. My way of tackling that was creating a “while()” function that would randomize their position again if their coordinates were equal.

This led me to a different issue: at times, when the character clicks on the politician after their coordinates were reorganized (because they matched as mentioned in the paragraph earlier) the code would consider that to be clicking on the mole and would lead to a loss. I minimized the issue to the best of my abilities by decreasing the range of coordinates that would be considered a “click” for the mole. Despite minimizing that, there is still that probability.

Future improvements:

In the future, I would definitely want to improve the issue mentioned in the previous paragraph in a way that would leave no room for the possibility of losing if the politician was clicked. In the same vein, I would also want to create a more efficient way to match the coordinates of the characters to the coordinates of the ellipses. Despite using the double array, the values within the array were hard-coded.

I would also like to make the design of the characters more game-like by having them appear from under the hole as opposed to simply popping up. I believe that it would make the interaction more user-friendly.

Overall, despite certain issues within the code, I am proud of my work as someone who is learning programming for the first time, and I believe I was able to create a game that the user can play, restart, and enjoy.

Midterm Progress -Yerkebulan Imanbayev

For the midterm project, I was inspired by a famous game that appears in all arcades – “Hit the Beaver”.


For this project, a user would be shown a window where they can start the game. When they start the game, they can pick two levels of difficulty. Once they pick their preferred level of difficulty, they are redirected to a new page. On this page, there are nine ellipses and periodically, beavers appear from the ellipses and the user has to click on the as soon as possible before they disappear. There will be a certain amount of beavers that will appear in the short period of time and if the user is able to catch all of them during the given time, they win. However, if they are not, they lose the game. Then they are given a chance to restart the game. The reason why there is two levels of difficulty is twofold: if the user picks a more difficult level, more beavers will appear in the same span of time AND they will be appearing and disappearing at a higher speed. 

Yerkebulan Imanbayev – Home Work 4

For this project, I was inspired by a video piece that was meant to spread awareness about dyslexia and how dyslexic people perceive written text.

Link to the video: https://drive.google.com/file/d/1A8b0rKX24hairV4tFCItGpdnE2iSorkR/view?usp=sharing

With this assignment, I tried to create a disorienting feeling initiated by written text that would allow the user to understand the condition of dyslexia. The words appear in different sizes and move, similar to the way the words move in the clip.

display(){
fill(this.textColor);
this.textColor = this.textColor+1;
textSize (this.Size);
textFont(newFont);
this.textX = this.textX + 1;//allows the words to move to the right
text(splitString,this.textX,this.textY);
if(this.textX>400) {
this.textX = -70;//allows the word to move back to its initial position
}
}

I used a class in order to make more words appear on the screen. In the piece of code included above, I made the text move so that once it’s out of the frame, it re-enters from the other side of the screen. Furthermore, I wanted the text to change and attain a different speed when the screen is clicked.

For the future, I want to be able to code it so that new words appear as the screen is clicked. Furthermore, I want the words to move in a more chaotic manner. Overall, I want to gain more knowledge on the tools that would allow me to convey a deeper sense of disorientation.