Link to Sketch (Please Press Space Bar for it to be in Full Screen): https://editor.p5js.org/am.almh/full/7XY6Q1OrX
Before actually developing my game, my initial idea was to create a Mario-inspired pac man game, in which Mario and Luigi go around a maze to collect stars while being chased by ghosts. In my eyes, the game would be a perfect blend of two retro games, creating a very nostalgic experience for users, particularly those who played both games growing up. However, as I was attempting to implement such a game in p5, I realized that such a project would be too advanced for my skill level and given the time constraints, I would not be able to create a fleshed out version of the game.
Initial Game Design
After countless hours of thinking of another idea, I came up with a simple, yet exciting, game in which the player chases stars across the sketch in order to win the game, which is why I called the game, Star Chaser. Ultimately, the focus shifted into a much simpler game centered around chasing stars and avoiding shells, still retaining the essence of retro Nintendo games that I was initially going for. It ensured that even with the changes to the game I was creating, the main concept of classic Nintendo games remained prominent. Thus, while the project may have evolved from its original idea, the concept of celebrating retro Nintendo games still remains.
Final Game Design
In my game, Star Chaser, players are able to control a Mario character using the arrows on the keyboard in order to collect stars and avoid incoming shells. The objective of the game is to catch all the stars within the given time limit, 30 seconds, trying to preserve Mario’s lives. Each time Mario gets hit by a shell, he loses one of his two lives. To win the game, the player must avoid the shells and achieve the maximum score of 60 points. This is done by maneuvering Mario around the sketch to collect all the stars.
Screen 1- Landing Page
Screen 2- Instructions Page
Screen 3- Game Page
Screen 4- Win Page
Screen 5- Lose Page
The aspect of my project I am particularly proud of is the actual game design. Initially, it was incredibly difficult for me to get things to move for the game, set up the lives and scores board, and even simply get the character to move. Although we did discuss some of these things in class, it was still quite difficult to do it myself given the fact that as I was attempting to put the game together, there were a lot of bugs and errors that kept occurring. Due to the fact that this was my first time creating a game, I had to sit for hours trying to figure out what kept causing the errors. However, after countless hours of attempting to understand the root cause of the problems, I was able to figure out that it was due to the order of the code and wrongly declaring variables. Although this was frustrating, I am proud that I was able to fix this issue and implement somewhat smooth controls for the game, which can be seen in the code below:
// Function to display the game screen
function gameScreen(){
// Sets background color to Green
background('#92CA5B');
// Displays grass images
//Right Side
image(grass, 0, 0, 1500, 1800);
//Left Side
image(grass, 780, 0, 1500, 1800);
// Displays stars
for (let i = 0; i < stars.length; i++) { // Loop through stars array
stars[i].display();
}
// Displays shells and handle their movement
for (let i = 0; i < shells.length; i++) { // Loop through shells array
shells[i].move(); //Moves Shells
shells[i].bounce(); //Helps Shells Bounce around Sketch
shells[i].display(); //Helps Display Shells on Sketch
}
//Draws a Rectangle for Information Boxes on Top of Sketch
//Right Box
fill('rgba(255,255,255,0.83)');
stroke('rgba(255,255,255,0.83)')
rect(40, 35 , 370, 70, 20);
//Left Box
fill('rgba(255,255,255,0.83)');
stroke('rgba(255,255,255,0.83)')
rect(1030, 35 , 370, 70, 20);
// Ensures in-game music is looping
if (!inGameMusic.isPlaying()) {
inGameMusic.loop();
}
// Ensures in-game music is playing
if (!inGameMusic.isPlaying()) {
inGameMusic.play();
}
// Displays the Player's Score
textFont("Mina");
fill('black');
stroke('white');
strokeWeight(3);
textSize(30);
text('Points:', 58, 80);
text(score, 168, 80);
// Displays the Player's Remaining Lives
textFont("Mina");
fill('black');
stroke('white');
strokeWeight(4);
textSize(30);
text('Lives:', 280,80 );
text(lives, 370, 80);
// Calculates and display the remaining time
landingTime = landingTime;
//Calculates the Game Time by Subtracting the Landing Time from the Current Total Time to then Converting the Results to Seconds by Dividing by 1000 and rounding down using the int() function.
gameTime = int((totalTime-landingTime)/1000);
// Displays text indicating time remaining
textFont("Mina");
fill('black');
stroke('white');
strokeWeight(3);
textSize(30);
text('Time Remaining:', 1070, 80);
//Displays the calculated remaining time
text(timeLimit - gameTime, 1316, 80);
//Game Outcomes
//If the score reaches 60 (maximum number of points) then the game will stop and take you to the win screen
if (score>=60){
inGameMusic.stop();
gameStage = 3;
winSong.play();
}
//If lives reach 0 then the game will stop and take you to the lose screen
if (lives<=0){
inGameMusic.stop();
gameStage = 4;
loseSong.play();
}
//If time reaches 0 then the game will stop and take you to the lose screen
if (gameTime>=timeLimit){
inGameMusic.stop();
gameStage = 4;
loseSong.play();
}
// Arrow keys pressed to move the player accordingly
//Left Arrow
if (keyIsDown(LEFT_ARROW)) {
playerDirection = -1; // Set direction to left
p1X -= 12; // Move left
//Right Arrow
} else if (keyIsDown(RIGHT_ARROW)) {
playerDirection = 1; // Set direction to right
p1X += 12; // Move right
}
//Up Arrow
if (keyIsDown(UP_ARROW)) {
p1Y -= 12; // Move up
}
//Down Arrow
else if (keyIsDown(DOWN_ARROW)) {
p1Y += 12; // Move down
}
// Moves the player within canvas boundaries
p1X = constrain(p1X, pWidth / 2, width - pWidth / 2); // Constrain x position
p1Y = constrain(p1Y, 0, height - pHeight); // Constrain y position
// Draws the image based on player direction
if (playerDirection === -1) {
// Flips the image horizontally when moving left
scale(-1, 1); // Flips horizontally
image(mario, -p1X, p1Y, pWidth, pHeight); // Draws image
scale(-1, 1); // Resets scale
} else {
// Otherwise, draws the image normally
image(mario, p1X, p1Y, pWidth, pHeight); // Draw image
}
// Check for collision between player and stars
for (let i = 0; i < stars.length; i++) {
if (stars[i].checkCollision(p1X, p1Y, pWidth, pHeight)) {
// Remove the collided star from the array
stars.splice(i, 1);
// Increase the score by 5 points
score += 5;
}
}
}
Another aspect that I am proud of is the visual and auditory elements of the game. I have incorporated hand drawn elements and sound effects from different Mario games in order to create a holistic experience for users and immerse them into the nostalgic game I created.
Hand Drawn Title
I believe doing this successfully captured the concept of Nintendo games I was trying to showcase to users and offers users an engaging experience. The code for this can be seen below:
//Helps transition back to the landing page when the button is pressed
if (mouseX >= 580 && mouseX <= 910 && mouseY >= 500 && mouseY <= 695 && mouseIsPressed == true){
//Moves to gameStage 0, which is landing page page
gameStage = 0;
//When button is pressed mainButtonSound will play
mainButtonSound.play();
}
Example of Where I Used Audio in my Game
In terms of improvements, I feel like I can incorporate more audio and visual elements to create a more immersive experience. I could potentially add a loading or waiting screen in between the game and instruction screens to make the game design more comprehensive. I also could have added some form of computer vision. I feel like it would make the design complex and creative, which can make it an engaging, unique, and enjoyable experience for users.
In regards to problems, I feel like my main issue, although quite silly, is the sprite sheet. I could not find any sprite sheet online that worked well with my game concept. Although that is the case, I tried finding anything just so I could get started with my game design. When I found one that could work as a placeholder, p5 would not load the image onto the sketch. I kept getting an error message from p5. I then tried to draw my own sprite sheets, which also did not work on p5. This problem was very frustrating because it was essentially the most important element of the game. Therefore, I had to stick to using a singular image to help move the character around. The image was of the character facing the right. Thus, I made the character flip horizontally when the left arrow key was pressed to add more movement to the character and the game experience as a whole.
Initial Sprite Sheet
Final Character Design
Overall, this project pushed me to learn more about p5 programming and how I am able to manipulate code to create what I wanted. This project, although difficult, was one of the most rewarding thing I have ever done. I am proud of how far I have come with p5 and I genuinely believe that this project shows my progress thus far.