xxxxxxxxxx
295
let game; //variable used as Game class object
let crosshair; //Crosshair objec
let font;
let enemies = []; //array of enemy objects
let frame; //variable used to record the starting frame of the game to use for countdown
let time = 62; //variable to set how long the game lasts + wait time for results screen (5 seconds + 2 seconds)
let startingTime; //used to create a delay when results screen shows up so that the next game doesn't start immediately if the user accidentally clicks the screen
let gunReloadSound;
let gunFireSound;
function preload() {
font = loadFont("assets/font.ttf"); //loading the font
enemy = loadImage("assets/enemy.png"); //the enemy png
gunDrawSound = loadSound("assets/gunDraw.wav"); //gun draw sound to be used when the game starts
gunFireSound = loadSound("assets/gunFire.wav"); //gun fire sound to be used each time the user shoots
enemyHit = loadSound("assets/enemyHit.wav"); //audio feedback for when an enemy is hit
gunFireSound.setVolume(0.2); //reducing the volume of the gun fire sound so that the enemyHit sound can be heard clearly
}
function setup() {
createCanvas(960, 540); //this resolution was picked to prevent the backgrounds from appearing stretched or compressed
game = new Game(); //creating the game object
crosshair = new Crosshair(); //creating the crosshair object
noCursor(); //hiding the cursor so that only the crosshair shows on the screen
textAlign(CENTER);
imageMode(CENTER);
for (let i = 0; i < 3; i++) {
//for loop to create 3 enemies
enemies[i] = new Enemy();
}
}
function draw() {
if (game.state == 0) {
game.menu();
} else if (game.state == 1) {
game.instructions();
} else if (game.state == 2) {
game.game();
for (let i = 0; i < 3; i++) { //drawing each enemy using for loop
enemies[i].drawEnemy();
}
} else if (game.state == 3){
game.endScreen();
}
crosshair.drawCrosshair(); //drawing the crosshair over everything else
}
function mousePressed() {
let x = mouseX; //passing the mouseX and mouseY values to local variables
let y = mouseY;
switch (game.state) {
case 0:
menuClick(x, y);
break;
case 1:
instructionsClick(x, y);
break;
case 2:
gameClick(x, y);
break;
case 3:
endScreenClick(x,y);
break;
}
}
function menuClick(x, y) {
if (
x < width / 2 + 150 &&
x > width / 2 - 150 &&
y < height / 2 + 50 &&
y > height / 2 - 50
) {
//dimensions for the play button
game.state = 1;
} else if (
x < width / 2 + 275 / 2 &&
x > width / 2 - 275 / 2 &&
y < height / 2 + 105 + 75 / 2 &&
y > height / 2 + 105 - 75 / 2
) {
//dimensions for the crosshair button
if (crosshair.length > 40) {
//this is used to reset the crosshair to its original size so that it doesn't get endlessly bigger
crosshair.length = 10;
crosshair.gap = 5;
} else {
crosshair.length += 10; //incrementation of crosshair variables
crosshair.gap += 3;
}
} else if (
x < width / 2 + 75 &&
x > width / 2 - 75 &&
y < height / 2 + 240 + 25 &&
y > height / 2 + 240 - 25
) {
//dimensions for the quit button
print("quit");
}
}
function instructionsClick(x, y) {
game.state = 2; //moving to the next game state when the user clicks the mouse
frame = frameCount; //records the frame number when the game starts
gunDrawSound.play();
}
function gameClick(x, y) {
gunFireSound.play();
let hit = false; //creating a variable to detect hits
for (let i = 0; i < 3; i++) { //looping through each enemy
if (
x < enemies[i].x + enemy.width / 8 &&
x > enemies[i].x - enemy.width / 8 + 30 &&
y < enemies[i].y + enemy.height / 8 &&
y > enemies[i].y - enemy.height / 8
) {
//using /8 because the image is already scaled down by 4 so I need to divide it by 2 again because imageMode(CENTER) is being used. The + 30 exists to make sure a hit is not registered when the enemy is shot below the arm, however this means shots on the enemy's arm sticking out to the left aren't registered.
enemyHit.play();
hit = true;
game.targetsHit++;
game.increaseScore();
enemies[i].moveEnemy(); //move location of enemy to make it seem like a new enemy spawns in a different location
break; //breaking the loop to ensure that only one enemy is hit with each mouse click
}
}
if (!hit) {
game.targetsMissed++;
game.decreaseScore();
}
}
function endScreenClick(x,y){
if (time <= 0){ //resetting variables when the game restarts
game.state = 1;
time = 62;
game.targetsHit = 0;
game.targetsMissed = 0;
game.score = 0;
}
}
class Game {
constructor() {
this.state = 0; //starting game state
this.targetsHit = 0;
this.targetsMissed = 0;
this.score = 0;
this.highScore = 0; //starting high score
this.menuBackground = loadImage("assets/menu.jpg"); //image background for menu screen
this.gameBackground = loadImage("assets/gameBackground.jpg");
}
menu() {
push();
imageMode(CORNER);
image(this.menuBackground, 0, 0, width, height);
pop();
push(); //creating all the rectangles for the buttons
rectMode(CENTER);
fill(0);
rect(width / 2, height / 2, 300, 100, 20);
rect(width / 2, height / 2 + 105, 275, 75, 20);
rect(width / 2, height / 2 - 175, 750, 100, 20);
pop();
push(); //displaying all the text that will be in the buttons
fill(255);
textFont(font);
textSize(100);
text("Reflex Shot", width / 2, height / 2 - 150)
textSize(100);
text("PLAY", width / 2, height / 2 + 25);
textSize(25);
text("CHANGE CROSSHAIR", width / 2, height / 2 + 100);
text("SIZE", width / 2, height / 2 + 125);
pop();
}
instructions() {
background(0);
push();
fill(255);
textFont(font);
textSize(25);
text(
"Shoot the enemies as fast as possible to score points",
width / 2,
height / 2
);
text("Click anywhere to start", width / 2, height / 2 + 60);
pop();
}
game() {
push();
imageMode(CORNER);
image(this.gameBackground, 0, 0, width, height);
pop();
if ((frameCount-frame)%60 == 0){ //using frameCount to decrease the time remaining
time--;
}
push();
fill(255);
textFont("Georgia"); //Fonts I found online didn't work with punctuation and numbers so I swiched to Georgia for this wherever punctuation was needed
textSize(30);
let timeRemaining = time - 2; //time - 2 because 2 seconds in the time variable are reserved for the end screen
text("Time Left: " + timeRemaining + " Score: " + game.score, width / 2, height / 15);
pop();
if (time == 2){ //the game ends
this.setHighScore();
this.state = 3;
}
}
endScreen(){
if ((frameCount-frame)%60 == 0){ //wait time before the user can start the game again
time--;
}
background(0);
fill(255);
textSize(40);
text("Score: " + game.score, width/2, height/2 -150);
text("Targets hit: " + this.targetsHit, width/2, height/2 - 100);
text("Targets missed: " + this.targetsMissed, width/2, height/2 - 50);
let accuracy, avgTime;
if (this.targetsHit != 0){ //preventing division by 0
accuracy = (this.targetsHit/(this.targetsHit + this.targetsMissed))*100;
avgTime = (60)/this.targetsHit;
} else {
accuracy = 0;
avgTime = 0;
}
text("Accuracy: " + nf(accuracy, 2, 2) + "%", width/2, height/2);
text("Average time taken to hit a target: " + nf(avgTime, 1, 2) + "s", width/2, height/2 + 50);
text("High Score: " + this.highScore, width/2, height/2 + 100);
push();
fill(255);
textFont(font);
textSize(40);
text("CLICK ANYWHERE TO PLAY AGAIN", width / 2, height / 2 + 200);
pop();
}
increaseScore() {
this.score += 10;
}
decreaseScore() {
this.score -= 5;
}
setHighScore(){
if (this.score>this.highScore){
this.highScore = this.score;
}
}
}
class Crosshair {
constructor() {
this.length = 10;
this.gap = 5; //default crosshair settings
}
drawCrosshair() {
push();
stroke(0, 255, 255);
strokeWeight(4);
line(mouseX - this.gap, mouseY, mouseX - this.gap - this.length, mouseY);
line(mouseX + this.gap, mouseY, mouseX + this.gap + this.length, mouseY);
line(mouseX, mouseY - this.gap, mouseX, mouseY - this.gap - this.length);
line(mouseX, mouseY + this.gap, mouseX, mouseY + this.gap + this.length);
pop();
}
}
class Enemy {
constructor() {
this.x = random(enemy.width / 4, width - enemy.width / 4); //random x and y locations within a boundary so that the enemies don't spawn over text or at the edge of the canvas
this.y = random(enemy.height / 4, height - enemy.height / 4);
}
drawEnemy() {
image(enemy, this.x, this.y, enemy.width / 4, enemy.height / 4);
}
moveEnemy(){
this.x = random(enemy.width / 4, width - enemy.width / 4); //new locations for the enemy
this.y = random(enemy.height / 4, height - enemy.height / 4);
}
}