xxxxxxxxxx
583
/*
Created on Date: 10/3/2022
Code Summary:
This code shows the implementation of a game called circle eater that is very similar to the idea of pacman. It consists of 4 different game states which are main menu(start state),playing state, winning state and losing state.
To develop the game I used many concepts that we covered in class such as object oriented programming, loops, conditional statements and the use of image and sound files.
*/
let cnt = 0;
//initializing global variables that will be used in the code
let picture;
let mainCharacter;
let UPP = 100;
let DOWNN = 100;
let LEFTT = 100;
let RIGHTT = 100;
let changeState = 0;
let prevTime;
let currTime;
//setting the inital game state to start
let gameState = "start";
function preload() {
//loading a picture which will be a background for the game
picture = loadImage("backgroundPic.jpg");
//loading text font for the instructions text
txtFont = loadFont("HackbotFreeTrial-8MgA2.otf");
//loading different sound files to be used in the game
eatingSound = loadSound("coinUp.mp3");
winSound = loadSound("winSound.mp3");
lossSound = loadSound("lossSound.wav");
}
//setting a global array variable
let ghost = [];
function setup() {
createCanvas(400, 400);
background(255);
//creating an object of class main player
mainCharacter = new mainPlayer(240, 193, 22, 22, 30, 310);
//creating four objects of Enemy class and storing them in an array
ghost[0] = new Enemy(65, 90, 203, 255, 255);
ghost[1] = new Enemy(172, 180, 239, 81, 6);
ghost[2] = new Enemy(208, 270, 83, 210, 252);
ghost[3] = new Enemy(315, 300, 247, 201, 222);
}
function draw() {
//checking the current game state to choose which scene to draw
if (gameState == "start") {
startScreen();
}
if (gameState == "play") {
playScreen();
}
if (gameState == "win") {
winScreen();
}
if (gameState == "loss") {
lossScreen();
}
}
//a function that contains the code for the main menu of the game
function startScreen() {
//creating a main menu screen
image(picture, 0, 0);
instructions();
fill(247, 201, 222);
text("Press the button to start the game", 20, 350);
//if enter button is pressed change to the game scene
if (changeState == 1) {
gameState = "play";
prevTime = millis();
}
}
//This function includes instructions to be displayed in main menu screen
function instructions() {
fill(252, 254, 27);
textStyle(BOLD);
textSize(35);
//using the preloaded font as a text font
textFont(txtFont);
text("PAC-MAN", 120, 70);
fill(83, 210, 252);
textSize(20);
//setting instructions to control the game
text("Instructions:", 130, 120);
textSize(15);
fill(239, 81, 6);
text("Avoid all moving ghosts", 105, 150);
text("Pass through 25 circles to win the game", 55, 180);
text("Control player with joystick", 85, 210);
}
function playScreen() {
background(0);
//draw the yellow ellipses on the screen across different parts of the screen
for (let i = 90; i < 350; i += 35) {
fill(255, 255, 0);
ellipse(65, i, 10);
ellipse(172, i, 10);
ellipse(208, i, 10);
ellipse(315, i, 10);
}
//draw the design of the maze
mazeDesign();
textSize(60);
//draw 4 enemy players and move them vertically across the screen
for (let k = 0; k < 4; k++) {
ghost[k].moveEnemy();
ghost[k].checkBounds();
ghost[k].drawEnemy();
//check if the main player will hit the enemy
ghost[k].checkLossState(mainCharacter.xPos, mainCharacter.yPos);
}
//draw main character and call different functions of the class
mainCharacter.drawPlayer();
currTime = int((millis() - prevTime) / 1000);
textSize(15);
text("Time: " + currTime, 300, 30);
mainCharacter.checkBoundsConditions();
mainCharacter.movePlayer();
mainCharacter.eatCircles();
mainCharacter.displayCount();
mainCharacter.checkWinningState();
}
//this function contains the code for the winning screen
function winScreen() {
background(0, 255, 0, 10);
fill(255, 0, 0);
textSize(20);
text("YOU WON THE GAME in " + currTime + " seconds", 60, height / 2);
text("Press the button to play again", 50, 300);
if (changeState == 1) {
changeState = 0;
gameState = "start";
prevTime = millis();
}
}
//this function contains the code for the losing screen
function lossScreen() {
background(255, 0, 0, 20);
fill(0);
textSize(20);
text("YOU LOST THE GAME", 100, height / 2);
text("Press the button to play again", 50, 300);
if (changeState == 1) {
changeState = 0;
gameState = "start";
prevTime = millis();
mainCharacter = new mainPlayer(240, 193, 22, 22, 30, 310);
}
}
//this function contains the code for the design of the maze
function mazeDesign() {
fill(0, 0, 255);
//top border of design
rect(50, 50, 300, 20);
//bottom border of the design
rect(50, 350, 300, 20);
//left border of design
rect(30, 50, 20, 320);
//right border of design
rect(330, 50, 20, 320);
fill(0);
strokeWeight(2);
stroke(0, 0, 255);
rect(80, 100, 80);
rect(80, 240, 80);
//left top and bottom square obstacles
rect(220, 100, 80);
rect(220, 240, 80);
rect(185, 100, 10, 80);
rect(185, 240, 10, 80);
//two middle borders in the design (horizontal ones)
rect(220, 205, 80, 10);
rect(80, 205, 80, 10);
noStroke();
}
class mainPlayer {
//defining constructor for the main player
constructor(posX, posY) {
this.xPos = posX;
this.yPos = posY;
this.size = 20;
this.startAngle = 30;
this.endAngle = 310;
this.xSpeed = 1;
this.ySpeed = 1;
this.count = 0;
this.prevCount = 0;
this.incrementedX = 65;
this.incrementedY = 30;
this.countIncremented = false;
}
checkBoundsConditions() {
// if right end is reached stop
// if the arc is equal to the border position minus radius of arc stop the player from moving
if (this.xPos >= 319) {
this.xPos = 319;
}
//if left end is reached stop
if (this.xPos <= 61) {
this.xPos = 61;
}
//if top end is reached stop
if (this.yPos <= 81) {
this.yPos = 81;
}
//if bottom end is reached also stop
if (this.yPos >= 350 - 11) {
this.yPos = 339;
}
//check if I hit the top left big block
if (
this.yPos >= 100 &&
this.yPos <= 180 &&
this.xPos >= 80 - 11 &&
this.xPos <= 160 + 11
) {
this.xSpeed = 0;
} else if (
this.yPos >= 100 - 11 &&
this.yPos <= 180 + 11 &&
this.xPos >= 80 &&
this.xPos <= 160
) {
this.ySpeed = 0;
}
//check if I hit the top right big block
else if (
this.yPos >= 100 &&
this.yPos <= 180 &&
this.xPos >= 220 - 11 &&
this.xPos <= 300 + 11
) {
this.xSpeed = 0;
} else if (
this.yPos >= 100 - 11 &&
this.yPos <= 180 + 11 &&
this.xPos >= 220 &&
this.xPos <= 300
) {
this.ySpeed = 0;
}
//check if I hit the bottom left big block
else if (
this.yPos >= 240 &&
this.yPos <= 320 &&
this.xPos >= 80 - 11 &&
this.xPos <= 160 + 11
) {
this.xSpeed = 0;
} else if (
this.yPos >= 240 - 11 &&
this.yPos <= 320 + 11 &&
this.xPos >= 80 &&
this.xPos <= 160
) {
this.ySpeed = 0;
}
// check if I hit the bottom right big block
else if (
this.yPos >= 240 &&
this.yPos <= 320 &&
this.xPos >= 220 - 11 &&
this.xPos <= 300 + 11
) {
this.xSpeed = 0;
} else if (
this.yPos >= 240 - 11 &&
this.yPos <= 320 + 11 &&
this.xPos >= 220 &&
this.xPos <= 300
) {
this.ySpeed = 0;
}
//if these conditions are not satisfied I set restore the original values of xSpeed and Y
else {
this.xSpeed = 1;
this.ySpeed = 1;
}
}
movePlayer() {
//based on the arrow change the direction of motion of the player and the start and end angles of the arc
if (LEFTT == 0) {
this.xPos -= this.xSpeed;
//change player Angle
this.startAngle = 220;
this.endAngle = 490;
} else if (RIGHTT == 0) {
LEFTT = 200;
UPP = 200;
DOWNN = 200;
this.xPos += this.xSpeed;
this.startAngle = 30;
this.endAngle = 310;
} else if (UPP == 0) {
this.yPos -= this.ySpeed;
this.startAngle = -40;
this.endAngle = 225;
} else if (DOWNN == 0) {
this.yPos += this.ySpeed;
this.startAngle = 120;
this.endAngle = 420;
}
}
eatCircles() {
//check if the main characters hits any circle, if yes increment the count
for (let i = 90; i < 350; i += 35) {
if (
this.xPos >= 65 - 11 &&
this.xPos <= 65 + 11 &&
this.yPos >= i - 11 &&
this.yPos <= i + 11
) {
fill(255, 0, 0);
ellipse(65, i, 10);
//only increment if current count equals previous count
//this is done to ensure the incrementation is not done infinitely
if (this.count == this.prevCount) {
this.countIncremented = true;
this.count += 1;
//play sound effect if a circle is eaten
eatingSound.play();
this.incrementedX = 65;
this.incrementedY = i;
}
} else if (
this.xPos >= 172 - 11 &&
this.xPos <= 172 + 11 &&
this.yPos >= i - 11 &&
this.yPos <= i + 11
) {
fill(255, 0, 0);
ellipse(172, i, 10);
if (this.count == this.prevCount) {
this.countIncremented = true;
this.count += 1;
eatingSound.play();
this.incrementedX = 172;
this.incrementedY = i;
}
} else if (
this.xPos >= 208 - 11 &&
this.xPos <= 208 + 11 &&
this.yPos >= i - 11 &&
this.yPos <= i + 11
) {
fill(255, 0, 0);
ellipse(208, i, 10);
if (this.count == this.prevCount) {
this.countIncremented = true;
this.count += 1;
eatingSound.play();
this.incrementedX = 208;
this.incrementedY = i;
}
} else if (
this.xPos >= 315 - 11 &&
this.xPos <= 315 + 11 &&
this.yPos >= i - 11 &&
this.yPos <= i + 11
) {
fill(255, 0, 0);
ellipse(315, i, 10);
if (this.count == this.prevCount) {
this.countIncremented = true;
this.count += 1;
eatingSound.play();
this.incrementedX = 315;
this.incrementedY = i;
}
}
//if non of the conditions are true and count is not zero increment the previous count, to allow for the count to increase again
else if (
this.countIncremented == true &&
(this.xPos > this.incrementedX + 11 ||
this.xPos < this.incrementedX - 11 ||
this.yPos > this.incrementedY + 11 ||
this.yPos < this.incrementedY - 11)
) {
this.prevCount += 1;
this.countIncremented = false;
}
}
}
//function that displays the current score
displayCount() {
fill(0, 255, 0);
textSize(15);
text("Current Score is " + this.count, 30, 30);
}
//this function checks if the winning state is achieved
checkWinningState() {
//the game is won if the count equals 15
if (this.count == 25) {
this.count = 0;
this.prevCount = 0;
//after winning the game move to the win state and reinitialize the main character object
gameState = "win";
eatingSound.stop();
winSound.play();
mainCharacter = new mainPlayer(240, 193, 22, 22, 30, 310);
}
}
//this function draws the mainPlayer
drawPlayer() {
fill(0, 255, 0);
arc(
this.xPos,
this.yPos,
this.size,
this.size,
radians(this.startAngle),
radians(this.endAngle)
);
}
}
class Enemy {
constructor(posX, posY, Rcolor, Gcolor, Bcolor) {
this.posX = posX;
this.posY = posY;
this.xSpeed = 0;
this.ySpeed = 1;
this.Rcolor = Rcolor;
this.Gcolor = Gcolor;
this.Bcolor = Bcolor;
}
//move the enemy vertically
moveEnemy() {
this.posY += this.ySpeed;
}
//check if the enemy hits the bounds, if yes reverse direction
checkBounds() {
if (this.posY >= 350 - 11 || this.posY < 81) {
this.ySpeed = -this.ySpeed;
}
}
//draw enemy using three arcs and a rectangle
drawEnemy() {
fill(this.Rcolor, this.Gcolor, this.Bcolor);
arc(this.posX, this.posY, 20, 20, radians(180), radians(360));
rect(this.posX - 10, this.posY, 20, 20);
fill(0);
arc(this.posX - 5, this.posY + 20, 10, 20, radians(180), radians(360));
arc(this.posX + 5, this.posY + 20, 10, 20, radians(180), radians(360));
}
//check if the player loses the game by hitting an enemy
checkLossState(mainPlayerXpos, mainPlayerYpos) {
if (
mainPlayerXpos >= this.posX - 15 &&
mainPlayerXpos <= this.posX + 15 &&
mainPlayerYpos >= this.posY - 10 &&
mainPlayerYpos <= this.posY + 10
) {
lossSound.play();
gameState = "loss";
}
}
}
function keyPressed() {
if (key == " ") {
// important to have in order to start the serial connection!!
setUpSerial();
}
}
function readSerial(data) {
////////////////////////////////////
//READ FROM ARDUINO HERE
////////////////////////////////////
if (data != null) {
// make sure there is actually a message
// split the message
let fromArduino = split(trim(data), ",");
// if the right length, then proceed
if (fromArduino.length == 5) {
// only store values here
// do everything with those values in the main draw loop
UPP = fromArduino[0];
DOWNN = fromArduino[1];
RIGHTT = fromArduino[2];
LEFTT = fromArduino[3];
changeState = fromArduino[4];
}
}
}
// int upPin = A1;
// int rightPin = A0;
// int leftPin = A3;
// int downPin=A4;
// int UP = 0;
// int RIGHT = 0;
// int LEFT = 0;
// int DOWN=0;
// int switchState;
// void setup() {
// // initialize serial communications at 9600 bps:
// Serial.begin(9600);
// pinMode(downPin,INPUT_PULLUP);
// pinMode(upPin, INPUT_PULLUP);
// pinMode(rightPin, INPUT_PULLUP);
// pinMode(leftPin, INPUT_PULLUP);
// // For versions prior to Arduino 1.0.1
// // pinMode(buttonPin, INPUT);
// // digitalWrite(buttonPin, HIGH);
// }
// void loop() {
// switchState=digitalRead(12);
// UP = digitalRead(upPin);
// RIGHT = digitalRead(rightPin);
// LEFT = digitalRead(leftPin);
// DOWN=digitalRead(downPin);
// //Serial.print("UP: ");
// //Serial.print(" | UP: ");
// Serial.print(UP);
// Serial.print(',');
// //Serial.print(" | DOWN: ");
// Serial.print(DOWN);
// Serial.print(',');
// //Serial.print(" | RIGHT: ");
// Serial.print(RIGHT);
// Serial.print(',');
// //Serial.print(" | LEFT: ");
// Serial.print(LEFT);
// Serial.print(',');
// Serial.println(switchState);
// delay(100); // add some delay between reads
// }