Skip to content

Instantly share code, notes, and snippets.

@james-innes
Created April 25, 2020 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james-innes/67f2491f1ca2b1f87a297dfe51bef9b4 to your computer and use it in GitHub Desktop.
Save james-innes/67f2491f1ca2b1f87a297dfe51bef9b4 to your computer and use it in GitHub Desktop.
Bears The Game P5.js
<!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