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.
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.
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 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.
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.