Final Project

sketchDownload
 /*
Rachel Kim
Section C
rachelki@andrew.cmu.edu

Nicholas Wong 
Section A 
nwong1@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();
		}

	}
}




To run this program, simply press space.

This game is a side-scrolling platform game, where the screen constantly scrolls and the player can only jump.
The goal of the game is to not touch any covid particles and to not fall of the edge of the screen. The longer you survive, the faster the screen scrolls.

We created a side-scrolling game because we thought it would be fun. The theme was around Covid to stay relevant. A side-scrolling game proved to be somewhat challenging due to the dynamic collision detection. Checking bounds and making particles bounce off of things were covered in class, however it was a little harder to implement that in a game where we needed to know exactly where the player collided with an object, and how to deal with positioning the player during/after the collision. Due to time constraints, we did not have much time to play-test the game. For example, we realized only after implementing the graphical elements that the game was pretty hard to read; the player and covid obstacles constantly blended in with the background, making it hard to see where everything was.

Overall, if we had more time, we would have refined the collision detection system and added in an actual algorithm for creating obstacles and platforms, as currently they are being randomly generated and do not take into account whether it is possible to ‘beat’ or ‘pass’ any given set of platforms or obstacles. Also, we would implement sound.

Done by Rachel Kim and Nicholas Wong.

Leave a Reply