/*
15-104
FINAL PROJECT
*/
/*
COLLABORATORS:
NICHOLAS WONG
SECTION A
nwong1@andrew.cmu.edu
RACHEL KIM
SECTION C
rachelki@andrew.cmu.edu
*/
//Every function has a comment before it showing who did the majority of the code: Nick, Rachel, or both of us.
//For functions that we did together, specific blocks, statements, and expressions are commented to show who did them.
//Player properties
var gravity = 0.4;
var defaultSpeed = 2;
var jumpForce = 10;
var constantSpeed = 2;
var playerStartPos = 300;
var walkImage = [];
//Stage properties
var stagePos = 0;
var stageSpeed = 2;
//Game state properties
var points = 0;
var gameOver = false;
var startGame = false;
//Game object lists
var platforms = [];
var covids = [];
//Background object lists
var backgroundBuildings = [];
var backgroundObjects = [];
var clouds = [];
//Building images
var housesA;
var housesB;
var supermarket;
//Background images
var cloud;
var sky;
var ground;
//Misc Images
var lampPost;
var streetSign;
var covidImage;
//Preload images - Rachel Kim
function preload(){
// These URLs are for the individual walk cycle images,
var filenames = [];
filenames[0] = "https://i.imgur.com/URNRJvg.png";
filenames[1] = "https://i.imgur.com/dt8xXHQ.png";
filenames[2] = "https://i.imgur.com/jmhE5QQ.png";
filenames[3] = "https://i.imgur.com/twdsSdv.png";
filenames[4] = "https://i.imgur.com/HWf5XmA.png";
filenames[5] = "https://i.imgur.com/45onU9z.png";
filenames[6] = "https://i.imgur.com/ey2SDeI.png";
filenames[7] = "https://i.imgur.com/cG56PdF.png";
filenames[8] = "https://i.imgur.com/533xGwE.png";
for (var i = 0; i < filenames.length; i++)
{
walkImage[i] = loadImage(filenames[i]);
}
//loading images for use
//Background elements
lampPost = loadImage("https://i.imgur.com/zEDU732.png");
streetSign = loadImage("https://i.imgur.com/TJ9H37E.png");
housesA = loadImage("https://i.imgur.com/cwlJyQN.png");
housesB = loadImage("https://i.imgur.com/lmhZBn8.png");
supermarket = loadImage("https://i.imgur.com/Q0iAh9M.png");
//Further background elements
cloud = loadImage("https://i.imgur.com/4SgU4y8.png");
sky = loadImage("https://i.imgur.com/34BWtmE.png");
ground = loadImage("https://i.imgur.com/qLiqpgd.png");
//Covid obstacles
covidImage = loadImage("https://i.imgur.com/eJskXy6.png");
}
//Setup Function - Both Rachel and Nick
function setup()
{
createCanvas(600, 400);
rectMode(CENTER);
textAlign(CENTER);
translate(width/2,height/2)
pl1 = new createPlayer(50,250,0); //Create a new player at (50,250) - Nick Wong
//Unless otherwise noted, everything within the dashed lines was done by Rachel Kim:
//---------------------------------------------------------------------------------------------------------
//Create buildings
for (let i = 0; i < 60; i++)
{
backgroundBuildings.push(createBuildings(500*i, 120, round(random(0,2))));
}
//Create street items
for (let i = 0; i < 100; i++)
{
backgroundObjects.push(createStreetItems(400*i, 335, round(random(0,1))))
}
//Create clouds
for(let i = 0; i < 50; i++)
{
clouds.push(createClouds(500*i, random(100,0), random(0,1)));
}
//Create platforms
for (let i = 0; i < 100; i++)
{
var colour = color(random(50,150),150,random(50,150));
platforms.push(createPlatform(100*i + 300, random(100,290), random(50,120), random(20,15), colour));
}
//Create covid obstacles
for (let i = 0; i < 100; i++)
{
covids.push(createCovid(random(350,750)*i + 800, random(150,275)));
}
//-----------------------------------------------------------------------------------------------------------
// ***Note***
// The reason why we are not procedurally generating objects on the fly
// as the screen scrolls and instead instantiating everything in setup
// is because it messes with collision detection sometimes.
}
//Main update function - Both Rachel And Nick
function draw()
{
//Background sky and ground - Rachel Kim
image(sky, 0, 0, width, height)
image(ground, 0 , 240, width, height/2);
//Point calculation and display - Nick Wong
points = round(-stagePos/10);
textSize(14);
text("Points: " + points.toString(), 35,25);
//Unless otherwise noted, everything within the dashed lines was done by Nick Wong:
//------------------------------------------------------------------------------------------------------------
if(!gameOver & startGame)
{
push();
stagePos -= defaultSpeed; //Set scroll speed to default speed
translate(stagePos + playerStartPos,0); //Translate entire canvas by scroll speed
drawBackground(); //Draw background - by Rachel Kim
pl1.update(); //Update player
pl1.display(); //Update player display
//Update canvas display
for(let i = 0; i < platforms.length; i++)
{
platforms[i].display();
}
//Update covid obstacle display
for(let i = 0; i < covids.length; i++)
{
covids[i].display();
}
pop();
//Increase scroll and movement speed if total points is a multiple of 300
if(points % 300 == 0 & points > 0)
{
defaultSpeed += 0.5;
constantSpeed += 0.5;
}
}
//---------------------------------------------------------------------------------------------------------------
//Game over screen - Rachel Kim
else if(gameOver)
{
push();
translate(width/2, height/2);
textSize(32);
fill(0);
text("Game Over!", 10,0);
textSize(18);
text("You scored " + points.toString() + " points!", 10,30);
text("Press [Space] to restart");
pop();
}
//Start game screen (only shows up once) - Nick Wong
else if(!startGame)
{
push();
translate(width/2, height/2);
textSize(32);
fill(0);
text("Press [Space] to Start", 10,0);
pop();
}
}
//Draw background elements - Rachel Kim
function drawBackground()
{
//Loop through and draw clouds
for (let i = 0; i < clouds.length; i++)
{
clouds[i].display();
clouds[i].update();
}
//Loop through and draw buildings
for (let i = 0; i < backgroundBuildings.length; i++)
{
backgroundBuildings[i].display();
}
//Loop through and draw signs and lamps
for (let i = 0; i< backgroundObjects.length; i++)
{
backgroundObjects[i].display();
}
//Draw ground
push();
fill(141,156,141);
noStroke();
rectMode(CORNERS);
rect(-width, height - 100, width*100, height);
pop();
}
//Animate player character - Rachel Kim
function drawPlayer() //Loop through walk images
{
//Loop through at 1/5 speed
if (frameCount % 5 == 0)
{
this.index++
}
//Reset image when it reaches end of list
if(this.index >= 7)
{
this.index = 0;
}
image(walkImage[this.index],this.x,this.y - this.height/2,this.width,this.height)
}
//Update player - Both Rachel and Nick
function updatePlayer()
{
//Game over if player falls off stage - By Rachel Kim
if(this.x <= -stagePos - playerStartPos)
{
gameOver = true;
}
//Game over if player touches a covid particle - By Nick Wong
for(let i = 0; i < covids.length; i++)
{
if(this.x + this.width/2 >= covids[i].x - covids[i].width/2 & this.x - this.width/2 <= covids[i].x + covids[i].width/2 &&
this.y + this.height/2 >= covids[i].y - covids[i].height/2 && this.y - this.height/2 <= covids[i].y + covids[i].height/2)
{
gameOver = true;
}
}
//Unless otherwise noted, everything within the dashed lines was done by Nick Wong:
//-------------------------------------------------------------------------------------------------------------------------------------------
this.y += this.dy; // Add y velocity to y position
//Check if player is on ground (not platforms)
if(this.y > height - 100 - this.height/2)
{
//Set y velocity to 0 and y position to top of ground rect
this.dy = 0;
this.y = height - 100 - this.height/2;
this.grounded = true;
}
else
{
this.grounded = false;
}
//Calculate x speed
let previousLoc = this.x //Store previous x position
this.x += constantSpeed; //Add speed
let currentLoc = this.x //Store current x position
this.dx = currentLoc - previousLoc; //The difference between previous and current is dx
//Check platform collisions (still a bit buggy)
for(let i = 0; i < platforms.length; i++)
{
//Check boundary of player is colliding with boundary of platform
if(this.x + this.width/2 >= platforms[i].x - platforms[i].w/2 & this.x - this.width/2 <= platforms[i].x + platforms[i].w/2)
{
//Check boundary of player is colliding with boundary of platform
if(this.y + this.height/2 > platforms[i].y - platforms[i].h/2 && this.y - this.height/2 < platforms[i].y + platforms[i].h/2)
{
//Check if colliding with side of platform
if(this.dx > 0 && this.dy == 0)
{
constantSpeed = 0;
}
//Check if below platform
if(this.dy < 0) //If player is traveling up, player touch bottom of platform
{
if(this.y - this.height/2 > platforms[i].y)
{
this.y = platforms[i].y + platforms[i].h/2 + this.height/2 + 2; //Set position to bottom of platform
this.dy = 0 //Y speed to 0
}
}
//Check if on top of platform
if(this.dy > 0) //If player is traveling down, player touch top of platform
{
if(this.y + this.height/2 < platforms[i].y)
{
this.y = platforms[i].y - platforms[i].h/2 - this.height/2 + 2; //Set position to top of platform
this.dy = 0; //Set Y speed to 0
this.onPlatform = true; //On platform is true (can jump)
}
}
}
else
{
this.onPlatform = false //On platform is not true if not colliding
constantSpeed = defaultSpeed; //Set player speed to default
}
}
}
this.dy += gravity; //Add gravity
//-------------------------------------------------------------------------------------------------------------------------------------------
}
//Create player - Nick Wong
function createPlayer(px,py,pdy)
{
var player = {x: px, y: py, dx: 0, dy: pdy, width: 25, height:45, grounded: false, onPlatform: false, index: 0, display: drawPlayer, update: updatePlayer}
return player;
}
//Create platform - Nick Wong
function createPlatform(px,py,pw,ph,colour)
{
var platform = {x: px, y: py, w: pw, h: ph, colour: colour, display: drawPlatform}
return platform;
}
//Draw platform - Nick Wong
function drawPlatform()
{
push();
noStroke();
fill(this.colour);
rectMode(CENTER);
rect(this.x, this.y, this.w, this.h);
pop();
}
//Create Covid obstacle - Nick Wong
function createCovid(cx, cy)
{
var cvd = {x: cx, y: cy, width: 20, height: 20, display: drawCovid}
return cvd;
}
//Create Covid obstacle - Nick Wong
function drawCovid(cx, cy)
{
push();
image(covidImage, this.x, this.y, this.width, this.height);
pop();
}
//Create buildings - Rachel Kim
function createBuildings(bx, by, i)
{
var bdg = {x: bx, y: by, index: i, display: drawBuilding}
return bdg;
}
//Render buildings - Rachel Kim
function drawBuilding()
{
var buildings = [housesA, housesB, supermarket]
image(buildings[this.index], this.x, this.y);
}
//Create lamps and signs - Rachel Kim
function createStreetItems(bx, by, i)
{
var items = {x: bx, y: by, index: i, display: drawStreetItems}
return items;
}
//Render lamps and signs - Rachel Kim
function drawStreetItems()
{
push();
scale(0.5,0.5); //Scale because too big
var streetItems = [streetSign,lampPost]
image(streetItems[this.index], this.x, this.y);
pop();
}
//Create clouds - Rachel Kim
function createClouds(bx, by, s)
{
var cld = {x: bx, y: by, speed: s, display: drawCloud, update: updateCloud}
return cld
}
//Render clouds - Rachel Kim
function drawCloud()
{
image(cloud, this.x, this.y);
}
//Add speed to clouds - Nick Wong
function updateCloud()
{
this.x -= this.speed;
}
//Reset game by setting all values and lists to default - Nick Wong
function resetGame()
{
covids = [];
platforms = [];
clouds = [];
backgroundBuildings = [];
streetItems = [];
stagePos = 0;
defaultSpeed = 2;
constantSpeed = 2;
setup();
startGame = true;
gameOver = false;
}
//Spacebar input - Both Rachel and Nick
function keyPressed()
{
//Spacebar is pressed
if(keyIsDown(32))
{
//Check if not in air - Nick Wong
if(pl1.grounded || pl1.onPlatform)
{
pl1.dy -= jumpForce; //Jump if player is not in the air
}
//Reset game if game over - Rachel Kim
if(gameOver)
{
resetGame();
}
//Start game if first time opening - Rachel Kim
if(!startGame)
{
resetGame();
}
}
}
For the final project, we wanted to create a side-scrolling game that related to Covid-19. In order to start the game, the only thing that the user needs to do is press the space bar in order for the player to jump. This type of game presents a screen that continuously scrolls while the player jumps to avoid obstacles. Two obstacles that the player faces are Covid-19 particles and platforms. The more obstacles the player overcomes, the speed of the game also increases as well. Once the player fails to avoid the Covid-19 particles or overcome the platforms, the player loses the game, and the “Game Over” screen would show up. In order to restart the game, the user would have to press the space bar. Overall, we both thought it would be fun to create a side-scrolling game for the final project of this course.
Throughout the process of this project, we faced a few challenges such as dynamic collision detection and graphical elements. Therefore, with time constraints, we were not able to play-test the game as much as we wanted to. Although there are a couple of flaws to the game, we had fun being able to create a side-scrolling game with colorful visuals. If we had more time, we would have refined the dynamic collision detection system, added in a more specific algorithm for creating obstacles and platforms, and fix the colors of the graphical elements. Additionally, we would also think about incorporating power-ups (masks, hand sanitizer, etc.) and sound as well.