Created
April 25, 2020 16:06
-
-
Save james-innes/67f2491f1ca2b1f87a297dfe51bef9b4 to your computer and use it in GitHub Desktop.
Bears The Game P5.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Bears! The Game</title> | |
<style> | |
html, body { | |
padding: 0; | |
margin: 0; | |
} | |
iframe | |
{ | |
overflow-x:hidden; | |
overflow-Y:hidden; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/p5.js"></script> | |
<script> | |
//variables with global scope | |
//*Most variables left as found | |
//implemented in 'drawBear' and also used in bounce functions to detect weather mouse has clicked the actual bear | |
var bearSize = 70; | |
//coordinates for location of bear originally used to decide where bear spawns | |
var bearX = 400; | |
var bearY = 0; | |
//configures how the bear bounces about and the speed at which it does this | |
var bearVelocityX = 3; | |
var bearVelocityY = 0; | |
var bounce = 0.7; | |
var gravity = 0.3; | |
var screen = 'start'; | |
//*'gameDuration' changed to 30 seconds | |
var gameDuration = 10; | |
var score = 0; | |
//*Cut from previous deceleration where it was being reset within same function that used it | |
var isTimeUp = false; | |
//draw initial background | |
function setup() { | |
//*'console.log()' addded in all function occurrences to trace progress when debugging | |
console.log('setup'); | |
createCanvas(800, 600); | |
} | |
//Main draw function calls others functions to draw screens | |
function draw() { | |
//Main background color set | |
background('#ffffff') | |
//Screen types set elsewhere and read here to determine what to do next | |
if (screen == 'start') { | |
//'startScreen' and 'endScreen' simple display and use of new button class while 'mainGame' primarily just calls other functions to create game experience | |
startScreen(); | |
} else if (screen == 'main') { | |
mainGame(); | |
} else if (screen == 'end') { | |
endScreen(); | |
} | |
} | |
//* original display code from 'startScreen' and 'endScreen' re-purposed within new 'button' class | |
class button { | |
constructor(label, x, y, w, h) { | |
this.label = label; //The text that will be displayed on the button | |
this.x = x; | |
this.y = y; | |
this.w = w; //width | |
this.h = h; //height | |
}; | |
//*New display method used to show the button but not provide any reaction | |
display() { | |
console.log('button.display') | |
fill('#DBFCFF'); | |
stroke('#CC4B09'); | |
strokeWeight(5); | |
//Hard-coded variables replaced with variables within class enabling it to be used to draw button in different locations | |
rect(this.x, this.y, this.w, this.h); | |
textFont('courier', 30); | |
noStroke(); | |
fill('#CC4B09'); | |
//Used simple operators to calculate additional variables instead of having them passed being unnecessarily being passed to function as they are relative to preexisting variables given | |
// values '100' and '45' should be changed in future so that they are relative to the width and height of the button | |
text(this.label, this.x + 100, this.y + 45); | |
}; | |
//*New pressed method replaces the two obsolete 'startScreenMousePressed' and 'endScreenMousePressed' functions and their associated logic which has been adapted below with variables being relative to the position specified for the button when instantiate a new instance of the 'button' class | |
pressed() { | |
console.log('button.pressed') | |
//using this method the logic of weather the mouse has been pressed is relative to the actual position at which it is drawn | |
if (mouseX > this.x && mouseX < (this.x + this.w) && mouseY > this.y && mouseY < (this.y + this.h)) { | |
//The method returns true if the mouse is pressed which tells the 'if' statement in 'mousePressed' function to call the necessary other code so that the button has some use | |
return true | |
}; | |
}; | |
}; | |
//*Instantiation of new intances of the 'button' class with given variables for the parameters explained above | |
var startButton = new button('Play', 300, 490, 200, 70) | |
let endButton = new button('Play Again', 300, 490, 200, 70) | |
//draws start screen | |
function startScreen() { | |
drawBear(400, 180, 200); | |
//*As well as colors fonts and stroke of buttons and main screen text has be altered | |
textFont("Comic Sans MS", 120); | |
textAlign(CENTER) | |
fill('#2a2a2a'); | |
noStroke(); | |
strokeWeight(10); | |
//Capitalization of text changed to match new choice of font | |
text('BEARS!', 400, 400); | |
textFont("Comic Sans MS", 30); | |
noStroke(); | |
fill('#2a2a2a'); | |
text('The Game', 400, 440); | |
//*New implementation of button class creating an instance of it with object 'startButton' which is then used to perform 'display' function | |
startButton.display(); | |
} | |
//draws end screen in much the same way as 'startScreen works' | |
//This could almost be refractured into a screen draw function but seems unnecessary | |
function endScreen() { | |
console.log('endScreen') | |
drawBear(400, 200, 200) | |
textFont("Comic Sans MS", 120) | |
textAlign(CENTER) | |
fill('#2a2a2a') | |
noStroke() | |
strokeWeight(10) | |
text('Game Over', 400, 400) | |
//again implementation of button class but this time using a new instance named 'endButton' | |
endButton.display(); | |
//*Code copied from 'startScreen' to draw final 'score' on end screen | |
textFont('courier', 30) | |
noStroke() | |
fill('#000000') | |
text('Score: ' + score, 400, 440) | |
} | |
//Start of game play | |
//Because the actual game play is a little more complicated it has been refactored | |
function mainGame() { | |
console.log('mainGame') | |
//* To maintain code quality new implementation of timer is made using 'timer()' function call | |
//Starts timer before anything else | |
timer() | |
//Refreshers location of bear | |
updateBear() | |
//looks to validate state of 'IsTimeUp' set in aforementioned 'timer()' function | |
checkIfGameOver() | |
drawBear(bearX, bearY, bearSize) | |
//*changes made to correct misspelling | |
//Responsible for drawing hedge | |
//This only needs to be called once but it would be very untidy to have the code for this declared within the 'mainGame' function so it is refractored | |
drawHedge() | |
drawInfo() | |
} | |
function updateBear() { | |
console.log('updateBear') | |
//changes the bears trajectory based on which side of the game space it hits so that it doesn't just fly off screen | |
bounceBear() | |
//Makes sure that bear bounces up from behind the hedge instead of just sitting there | |
resetVelocityIfHiding() | |
//Implements variables set from functions calls above to redraw the bear in its new location | |
moveBear() | |
} | |
function moveBear() { | |
console.log('moveBear') | |
bounceBear(); | |
//Adds value of 'bearVelocity' to existing corordinates of bear to make it progress across the screen | |
bearX += bearVelocityX | |
bearY += bearVelocityY | |
//Additional factor of gravity effects how the bear will always fall down behind the hedge | |
bearVelocityY += gravity | |
} | |
function bounceBear() { | |
console.log('bounceBear') | |
//*Simple example of refracturing where before code for these three functions was codded into 'bounceBear()' | |
bounceFloor(); | |
bounceLeft(); | |
bounceRight(); | |
} | |
//*Definitions of refactored bounce fucntions called in 'bounceBear()' | |
function bounceFloor() { | |
console.log('bounceFloor') | |
//Checks to see if bear has moved to or below the bottom of the screen | |
if (bearY + bearSize / 2 >= height) { | |
//inversion of 'verVelocity' is used with 'bounce' variable to give the appearance that the bear has hit the bottom and bounced off at speed | |
console.log('bounceFloor'); | |
bearVelocityY = -bearVelocityY * bounce; | |
bearY = (height - bearSize / 2) - 1; | |
} | |
} | |
function bounceLeft() { | |
console.log('bounceLeft') | |
if (bearX - bearSize / 2 <= 0) { | |
console.log('bounceLeft'); | |
bearVelocityX = -bearVelocityX * bounce; | |
bearX = (bearSize / 2) + 1; | |
} | |
} | |
function bounceRight() { | |
console.log('bounceRight') | |
if (bearX + bearSize / 2 >= width) { | |
console.log('bounceRight'); | |
bearVelocityX = -bearVelocityX * bounce; | |
bearX = (width - bearSize / 2) - 1; | |
} | |
} | |
//To make the game more fun a random variable is assinged to the velocity so that the bear makes a fun and unpredictable rebound from the floor | |
function resetVelocityIfHiding() { | |
console.log('resetVelocityIfHiding') | |
if (bearIsHiding()) { | |
bearVelocityX = random(-15, 15) | |
bearVelocityY = random(-10, -20) | |
} | |
} | |
function bearIsHiding() { | |
//This function actually checks for two things, weather the bear is hidden behind | |
console.log('bearIsHiding') | |
if (bearY > height - 50) { | |
if (abs(bearVelocityY) < 1) { | |
return true | |
} | |
} | |
//else if the above condition isn't met and the other return statement isn't used to exit the 'bearIsHiding' function then 'false' is returned | |
return false | |
} | |
//*Function of timer added | |
function timer() { | |
console.log('timer') | |
//'frameCount' returns the number of times the code has been run through at the rate of 60 per second | |
//'%' is the Modulo operator and is used to determine weather the frame count is divisible and if it is what that reminder is to determine how many seconds have passed | |
if (frameCount % 60 == 0 && gameDuration > 0) { | |
//each time a second has been found to have passed then the 'gameDuration' is decreased by one | |
gameDuration --; | |
} | |
//The less then or equal too operator must be used because with the draw function there is alot happening at the same time and so | |
if (gameDuration <= 0) { | |
//'CheckIfGameOver' will check to see weather 'isTimeUp' is set to 'true' or 'false' | |
isTimeUp = true | |
//Console logs such as those below are very helpful for debugging | |
console.log('isTimeUp: ' + isTimeUp); | |
console.log('gameDuration: ' + gameDuration); | |
} | |
} | |
function checkIfGameOver() { | |
console.log('checkIfGameOver') | |
if (isTimeUp) { | |
screen = 'end' //corrected from screen being set to 'game over' | |
} | |
} | |
function drawBear(x, y, size) { | |
//Lots of changes made here for color choice | |
noStroke(); | |
fill('#CC4B09'); | |
ellipse(x - size * 0.35, y - size * 0.35, size * 0.4); | |
ellipse(x + size * 0.35, y - size * 0.35, size * 0.4); | |
fill('#FFBAAA'); | |
ellipse(x - size * 0.35, y - size * 0.35, size * 0.3); | |
ellipse(x + size * 0.35, y - size * 0.35, size * 0.3); | |
fill('#CC4B09'); | |
ellipse(x, y, size); | |
fill('#FFBAAA'); | |
ellipse(x, y + size * 0.15, size * 0.4); | |
fill('#ffffff'); | |
ellipse(x - size * 0.2, y - size * 0.2, size * 0.2); | |
ellipse(x + size * 0.2, y - size * 0.2, size * 0.2); | |
fill('#443742'); | |
var angleFromBearToMouse = atan2(mouseY - y, mouseX - x); | |
var eyeOffsetX = cos(angleFromBearToMouse) * size * 0.05; | |
var eyeOffsetY = sin(angleFromBearToMouse) * size * 0.05; | |
ellipse(x - size * 0.2 + eyeOffsetX, y - size * 0.2 + eyeOffsetY, size * 0.08); | |
ellipse(x + size * 0.2 + eyeOffsetX, y - size * 0.2 + eyeOffsetY, size * 0.08); | |
ellipse(x, y + size * 0.08, size * 0.12); | |
stroke('#443742'); | |
strokeWeight(size * 0.05); | |
line(x, y + size * 0.08, x, y + size * 0.2); | |
line(x, y + size * 0.2, x - size * 0.05, y + size * 0.25); //Corrections made where variables had incorrect capitalization or wrong ones were used such as 'bearX' instead of 'X' | |
line(x, y + size * 0.2, x + size * 0.05, y + size * 0.25); | |
} | |
function drawHedge() { | |
console.log('drawHedge') | |
noStroke(); | |
//Used this line of code to determine how high the hedge is | |
rect(0, height - 70, width, 70); | |
for (var y = height - 70; y < height + 40; y += 11) { | |
if (y % 2 == 0) { | |
fill('#72d882'); | |
} else { | |
fill('#127C22'); | |
} | |
for (var x = 0; x < width + 40; x += 30) { | |
ellipse(x, y, 40); | |
} | |
} | |
} | |
function drawInfo() { | |
console.log('drawInfo') | |
//score | |
noStroke() | |
fill('#000000') | |
textFont('courier', 20) | |
textAlign(LEFT) | |
text('score: ' + score, 10, 25) | |
//timer | |
//code below was copied from existing code above with minor changes | |
noStroke() | |
fill('#000000') | |
textFont('courier', 20) | |
textAlign(LEFT) | |
text('timer: ' + gameDuration, 10, 40) | |
} | |
//*The use of the two functions 'startScreenMousePressed' and endScreenMousePressed' were replaced with the use of the new 'pressed' method defined in the new 'button' class where by if the method returned 'true' for the button being pressed then the 'if' statement would be be valid and continue to action the dessired effect of pressing the button such as for exmaple 'startGame' | |
function mousePressed() { | |
console.log('mousePressed') | |
if (screen == 'start') { | |
if (startButton.pressed()) { | |
startGame() | |
} | |
} else if (screen == 'main') { | |
gameMousePressed(); | |
} else if (screen == 'end') { | |
if (endButton.pressed()) { | |
reset(); | |
startGame(); | |
} | |
} | |
} | |
function gameMousePressed() { | |
console.log('gameMousePressed') | |
var xDist = mouseX - bearX; | |
var yDist = mouseY - bearY; | |
var mouseDistanceFromBear = Math.sqrt(xDist*xDist + yDist*yDist); | |
//*Small change made to the division of 'bearSize' below so that the player can only get a hit if they click directly on the bear rather then around | |
if (mouseDistanceFromBear < (bearSize / 2) && (mouseY < (height - 70))) { | |
score ++ //Small change made where proper '++' operator is used in favour of 'score = score + 1' | |
//makes sure that the bear will try and hide behind the push if it is hit | |
bearVelocityY = 15 | |
bearVelocityX = bearVelocityX * 2 | |
} | |
} | |
function startGame() { | |
console.log('startGame'); | |
screen = 'main'; | |
} | |
//*This fucntion has been created to allow the user to use the play again feature and start with fresh variables | |
function reset() { | |
screenType = 'start'; | |
gameDuration = 30; | |
score = 0; | |
isTimeUp = false; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment