xxxxxxxxxx
449
// Vivianna Mo
// Intro to IM - Michael Shiloh
// Dec. 12, 2022
// Final Project
let gameState = "start";
// variables for Arduino info
let button, gameButton;
let distance;
// images and class variables
let titleImg, bkgImg;
let endImg = [];
let instructionsImg = [];
let foods = [];
let addFoods = [];
// sound variables
let bkgSong, goodEndSong, badEndSong;
let eatSound;
let score = 0;
let highScore = 0;
let timer = 30;
function preload() {
bkgImg = loadImage("Assets/bkgImg.jpg");
titleImg = loadImage("Assets/titleImg.jpg");
for (let i = 0; i < 4; i++) {
instructionsImg[i] = loadImage("Assets/instructionImg" + i + ".png");
}
character = loadImage("Assets/noFace.png");
for (let i = 0; i < 5; i++) {
foods[i] = loadImage("Assets/food" + i + ".png");
}
badEndImg = loadImage("Assets/endImg0.gif");
goodEndImg = loadImage("Assets/endImg1.gif");
bkgSong = loadSound("Assets/themeSong.mp3");
eatSound = loadSound("Assets/eatSound.mp3");
badEndSong = loadSound("Assets/endSong0.mp3");
goodEndSong = loadSound("Assets/endSong1.mp3");
}
function setup() {
// createCanvas(755, 575);
createCanvas(windowWidth, windowHeight);
bkgSong.loop();
bkgSong.playMode("restart");
bkgSong.setVolume(0.7);
badEndSong.playMode("restart");
goodEndSong.playMode("restart");
eatSound.playMode("restart");
addFoods.push(new Food()); // This makes sure that the food keeps on getting added
}
function draw() {
if (gameState == "start") {
instructionScreen();
} else if (gameState == "play") {
drawGame();
} else if (gameState == "end") {
gameOver();
}
// print(addFoods.length);
// print(gameState);
}
function instructionScreen() {
background("#299F9E");
if (!bkgSong.isPlaying()) {
bkgSong.play();
}
// push();
// scale(1.2);
// image(titleImg, 40, height - 550);
// pop();
if (!serialActive) {
textSize(18);
fill("#3300027F");
text("Press Space Bar to select Serial Port", 20, 30);
} else {
textSize(18);
fill("#3300027F");
text("Connected", 20, 30);
}
textFont("Silkscreen");
fill("#A88572");
textSize(120);
text("feed no face", width / 2 - 480, height / 2 - 190);
fill("#D3B09A");
text("feed no face", width / 2 - 485, height / 2 - 193);
push();
noStroke();
fill("#C94541");
rectMode(CENTER);
rect(width / 2, height / 2 + 10, 650, 320, 20);
pop();
textSize(24);
fill("#E6A05A");
text("Press the black button to start", width / 2 - 255, height / 2 + 150);
// Instructions text
textSize(22);
fill("#330002");
textFont("Ubuntu");
text(
"1. Slide the physical No Face slowly left and right to mirror",
width / 2 - 305,
height / 2 - 80
);
text("the screen", width / 2 - 300, height / 2 - 50);
text(
"2. Catch the food items by pressing the button when the food",
width / 2 - 305,
height / 2 - 10
);
text(
" is near No Face's body on the screen",
width / 2 - 308,
height / 2 + 20
);
text(
"3. You have 30 seconds to catch as many foods as you can!",
width / 2 - 305,
height / 2 + 60
);
text(
"Get at least 10 or it won't end well...",
width / 2 - 305,
height / 2 + 90
);
// Instructions image
for (let i = 0; i < 4; i++) {
push();
image(instructionsImg[i], i * 300 + 200, height / 2 + 250);
pop();
}
if (gameButton == 1) {
gameState = "play";
}
// if (keyCode == ENTER) {
// gameState = "play";
// }
}
function drawGame() {
// Create the background image to fit the canvas size
bkgImg.resize(windowWidth, windowHeight);
image(bkgImg, 0, 0);
// Display the score
textSize(56);
textFont("Silkscreen");
fill(255);
text(score, width - 90, 80);
// Function for the timer
countdown();
// Function that draws the character
noFace();
// Flappy Bird Coding Challenge (The Coding Train):
// https://editor.p5js.org/codingtrain/sketches/FtBc2BhHM
for (let i = addFoods.length - 1; i >= 0; i--) {
addFoods[i].rainingFood();
addFoods[i].show();
}
if (frameCount % 100 == 0) {
// Adds new food to the array
addFoods.push(new Food());
} else if (frameCount % 250 == 0) {
addFoods.push(new Food());
}
}
function gameOver() {
bkgSong.stop();
if (score < 10) {
if (!badEndSong.isPlaying()) {
badEndSong.play();
}
background("#231F20");
push();
scale(1.4);
image(badEndImg, width / 2 - 480, height - 480);
pop();
// Keeps track of the best score
if (highScore < score) {
highScore = score;
} else {
highScore = highScore;
}
push();
textFont("Silkscreen");
fill("#BB4430");
textSize(75);
text("OH NO!", width/2 - 155, 100);
text("He's Hangry", width/2 - 285, 170);
textSize(44);
fill("#E7A64C");
text("SCORE: " + score, width / 2 - 140, height / 2 - 80);
text("BEST: " + highScore, width / 2 - 120, height / 2 - 40);
textSize(24);
fill(187, 68, 48, 150);
text("Press the black button to restart", width / 2 - 280, height / 2);
pop();
} else {
background("#68A061");
image(goodEndImg, width / 2 - 250, height - 320);
if (!goodEndSong.isPlaying()) {
goodEndSong.play();
}
// Keeps track of the best score
if (highScore < score) {
highScore = score;
} else {
highScore = highScore;
}
push();
textFont("Silkscreen");
fill("#D3B09A");
textSize(75);
text("Yay you did it!", width/2 - 380, 100);
text("He's full for now :D", width/2 - 480, 170);
textSize(44);
fill("#E7A64C");
text("SCORE: " + score, width / 2 - 140, height / 2 - 80);
text("BEST: " + highScore, width / 2 - 120, height / 2 - 40);
textSize(24);
fill("#D3B09ABA");
text("Press backspace to restart", width / 2 - 280, height / 2);
pop();
}
// Gets the value from the black button connected to arduino
// Since it is a lock switch, when it is 0 the game is start (doesn't check for previous button state)
if (gameButton == 0) {
gameState = "start";
badEndSong.stop();
goodEndSong.stop();
score = 0;
addFoods.splice(0, addFoods.length);
}
// if (keyCode == BACKSPACE) {
// gameState = "start";
// badEndSong.stop();
// goodEndSong.stop();
// score = 0;
// addFoods.splice(0, addFoods.length);
// }
}
// This adds the character no Face to the game
function noFace() {
push();
scale(0.7);
image(character, map(distance, 5, 32, 0, width), height + 150);
pop();
// Check the food eaten at the position of the character
for (let i = addFoods.length - 1; i >= 0; i--) {
if (
addFoods[i].checkFoodEatenAt(
map(distance, 5, 42, 0, width),
height - 50
) &&
button == 1 // Make sure the button is pressed to catch food
) {
addFoods.splice(i, 1);
score += 1;
}
if (addFoods[i].yPos > height + 50) {
addFoods.splice(i, 1);
}
}
}
function countdown() {
if (frameCount % 60 == 0 && timer > 0) {
timer--;
}
fill("red");
text(timer, 30, 80);
if (timer == 0) {
gameState = "end";
timer = 30;
}
}
function keyPressed() {
if (key == " ") {
// important to have in order to start the serial connection!!
setUpSerial();
}
}
// Arduino connection
function readSerial(data) {
// Get data from Arduino
if (data != null) {
// make sure there is actually a message
// split the message
let fromArduino = split(trim(data), ",");
// print(fromArduino)
// if the right length, then proceed
if (fromArduino.length == 3) {
// only store values here
// do everything with those values in the main draw loop
button = fromArduino[0];
gameButton = fromArduino[1];
distance = fromArduino[2];
}
// Send data from p5 to Arduino (not necessary in this case)
let sendToArduino = "0,0" + "\n";
writeSerial(sendToArduino);
}
}
// Arduino code
/*
// Distance sensor:
#define echoPin 8 // attach pin D2 Arduino to pin Echo of HC-SR04
#define trigPin 9 //attach pin D3 Arduino to pin Trig of HC-SR04
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
// Variables for smoothing the distance sensor
const int numReadings = 10;
int readings[numReadings];
int readIndex = 0;
int total = 0;
int average = 0;
int currentAverage = 0;
// Button variables
const int BUTTON = 5;
bool previousButtonState = false;
const int GAME_BUTTON = 11;
void setup() {
Serial.begin(9600);
pinMode(BUTTON, INPUT);
pinMode(GAME_BUTTON, INPUT);
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
// initialize all the readings to 0 for the distance sensor
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
// start the handshake
while (Serial.available() <= 0) {
Serial.println("0,0"); // send a starting message
delay(300); // wait 1/3 second
}
}
void loop() {
// wait for data from p5 before doing something
while (Serial.available()) {
// int left = Serial.parseInt();
// int right = Serial.parseInt();
if (Serial.read() == '\n') {
int buttonState = digitalRead(BUTTON);
int gameButtonState = digitalRead(GAME_BUTTON);
if (buttonState && !previousButtonState) {
Serial.print(buttonState);
}
previousButtonState = buttonState;
distanceSensor();
// Serial.print(buttonState);
Serial.print(",");
Serial.print(gameButtonState);
Serial.print(",");
Serial.println(currentAverage);
}
}
}
// Reference for smoothing the distance sensor readings: https://docs.arduino.cc/built-in-examples/analog/Smoothing
void distanceSensor() {
// Clears the trigPin condition
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Smoothing the distance sensor readings
total = total - readings[readIndex];
readings[readIndex] = distance;
total = total + readings[readIndex];
readIndex = readIndex + 1;
if (readIndex >= numReadings) {
readIndex = 0;
}
average = total / numReadings;
if (average >= 5 && average <= 42) {
// Serial.print("Distance: ");
// Serial.println(average);
// Serial.println(" cm");
currentAverage = average;
delay(1);
}
}
*/