The Flame Boy: Becoming a Robinson (Midterm Project)

Concept

link to full sketch: https://editor.p5js.org/takuthulani/full/gdL68sjHc

This project is an adaptation of a fictional world I’ve created, designed to offer an immersive storytelling experience. Instead of passively observing, users actively engage with the narrative, making it more like an interactive movie or book. The story centers around the protagonist and key events from his life. To preserve the element of surprise and keep the experience enjoyable, I encourage you to explore the story firsthand!The narrative also takes place in a sci-fi setting, featuring an alien planet inhabited by human-like beings with enhanced abilities. This concept influenced the design, with fire playing a central role and red as the dominant color theme.

How the Game Works:

The game starts by greeting the user with a cover page that plays The Flame Boy’s theme song (it’s catchy, so you might get lost in it—don’t forget to progress, though you’re welcome to just listen!). The theme song was created using Suno AI (credit to them). On the cover image, there are instructions to click on the screen, which takes the user to a menu page (with its own theme song as well from Pixabay). The menu presents two options: “His Story” and “His Home,” and the user is expected to click on one.

If the user clicks on “His Home,” the page transitions to an image showing his home—simple and straightforward. This image was made using DALL-E. To exit this view and return to the menu, the user can press the escape button. If the user clicks on “His Story,” a video begins to play, so sit back and enjoy! After the video, the user must make a choice: either “Trust” or “Don’t Trust” the character they interact with. Clicking “Don’t Trust” progresses the game to the conclusion and eventually to a thank you message. The user can return to the cover screen by pressing the mouse key.

If the user chooses “Trust,” the game transitions to a section where they need to earn 100 points to reach the story’s conclusion. The experience continues until the user decides to stop the sketch.

Parts I’m Proud of:

There are several aspects of this project that I’m truly proud of. First and foremost is the video element, which made everything possible. Initially, I planned to use images and recordings to narrate the story, but p5.js kept crashing, so integrating video became the best solution. Even though it’s technically “out of scope” based on what we covered in class, it was a practical way to bring the project to life. I turned to resources like Stack Overflow, the p5.js help section, and ChatGPT to guide me through the video implementation. Below is an example of the code I used to incorporate video into the project:

// Video elements
let storyVideo; // Video for the story sequence
let conclusionVideo; // Video for the conclusion sequence
let decisionImage; // Image for the decision screen where the player chooses their path
...
function playStory() {
  // Stop the story video if it's currently playing to reset the playback
  storyVideo.stop(); 
  
  // Reset the playback time of the story video to the beginning (0 seconds)
  storyVideo.time(0);  
  
  // Start playing the story video from the beginning
  storyVideo.play();  
}
...
function playConclusion() {
  // Stop the conclusion video if it is currently playing
  conclusionVideo.stop();
  
  // Reset the video playback time to the start (0 seconds)
  conclusionVideo.time(0);
  
  // Start playing the conclusion video from the beginning
  conclusionVideo.play();
}

Secondly, I’m particularly proud of the shooting game and its mechanics. I’ll include snippets of the code for the parts I’m most proud of below, and I’ll also provide a link to the full sketch so you can explore the many amazing functions I’ve implemented. Here’s a sample of the code for the game within the game:

function playShootingGame() {
  // Draw the background night sky for the shooting game
  drawNightSky();
  
  // Set the fill color to white for the score text
  fill(255);
  
  // Set the text size for the score display
  textSize(16);
  
  // Align text to the right and top of the canvas
  textAlign(RIGHT, TOP);
  
  // Display the current score at the top-right corner of the canvas
  text("Score: " + score, width - 10, 10);

  // Check if 2 seconds have passed since the last star was spawned
  if (millis() - starTimer > 2000) {
    // Spawn new stars for the shooting game
    spawnGameStars();
    
    // Update the star timer to the current time
    starTimer = millis();
  }

  // Loop through the stars array in reverse order to avoid issues with splicing
  for (let i = stars.length - 1; i >= 0; i--) {
    // Get the current star object from the stars array
    let star = stars[i];
    
    // Set the fill color to yellow for larger stars, white for smaller stars
    fill(star.size === 40 ? 'yellow' : 'white'); 
    
    // Draw the star as an ellipse at its specified x and y coordinates with its size
    ellipse(star.x, star.y, star.size);

    // Check if the star has been on screen for more than 2 seconds
    if (millis() - star.appearTime > 2000) {
      // Remove the star from the array if it has been displayed long enough
      stars.splice(i, 1);
    }
  }

  // Check if the score has reached 100 points
  if (score >= 100) {
    // Change the game state to 'conclusion'
    state = 'conclusion';
    
    // Play the conclusion video or sequence
    playConclusion();
  }
}

link to the sketch: <iframe src=”https://editor.p5js.org/takuthulani/full/gdL68sjHc”></iframe>

Problems I encountered and possible solutions:

The main challenge I faced was implementing video into the sketch after my original plan didn’t work out. I found solutions using the online resources mentioned earlier. Another problem was integrating the mini-game within the story. The best approach was to treat the game as a separate entity and then integrate it into the sketch, rather than seeing it as one large game (which added unnecessary stress while coding). Additionally, I encountered performance issues, as I used too many audio and visual files. Optimizing the game speed and performance became a key focus. Below is a screenshot showing some of the media I used:

files and resources used to generate the story for the game

This includes various assets like fonts, PowerPoint presentations, a mini script for the game, and a massive 500MB PSD file (trust me, you don’t want to know how many images are in that!). I also went through multiple iterations of the menu and cover page designs.

Since I’m not the best at drawing, I used Meta AI to generate the images, which I then manually edited in Photoshop. I recorded the vocal narrations using Audacity and assembled the video using CapCut before uploading it into my program. Some of the images, sounds, and music were sourced from Pixabay.com, which allows usage for projects like this.

Areas needing improvements:

The overall workflow of the game could use some enhancements. For example, the “His Home” area could feature more interactive functions to increase engagement and enjoyment. Additionally, the story’s flow would benefit from a clearer rationale for why the user needs to earn 100 points to advance to the conclusion. While some of these creative flaws may have been overlooked, they can be incorporated as features in future updates.

Overall, I thoroughly enjoyed working on this project and was fully invested, as I was creating something I loved, among other reasons. It provided a fun and technical way to learn, and I am excited for you all to see what I build as time progresses.

The following images are alternative designs that did not make the cut:

According to a few people, the guy on the right did not fit in well so this menu did not make it.
Although my overall theme was red and black, I did not think thiss would benefit the aesthetics of the overall story.
This was a test I did when I tried integrating mock-up text with my overall design.

 

 

 

 

MidTerm Project: Going Through It

Inspiration:

I’ve always had a fear of snakes. Overcoming it seemed impossible until I started working on my game. Inspired by how snakes consume food whole, I created “Going Through It”.  An obstacle course game where the obstacle course is designed in the shape of a snake. The player controls a small stick character trying to escape the snake as fast as possible. Adding my own unique twist to the game, the player cannot directly control the jumping ability of the stick figure, instead the stick is more akin to a ‘pogo stick’ where it bounces off with every obstacle it collides with and the player only controls the rotation of the stick figure using their keyboard.

Challenges Faced:

Developing “Going Through It” presented me with several challenges

  • Collision Detection: One of the primary difficulties was implementing an effective collision detection system that could handle the stick’s rotation and interactions with obstacles at various angles. Ensuring that the stick responds correctly to collisions, including bouncing off surfaces at appropriate angles, required careful calculation and testing. This is one of the primary features of the game and needed to be perfect although I am always sorting out minor issues with the collision detection mechanism.
  • Physics and Movement: Balancing the physics of gravity, friction, and rotational speed to create a challenging yet fun experience was another challenge. The stick couldn’t be too fast, the gravity couldn’t be too strong and the rotation had to be just right to be responsive yet precise. Fixing these problems involved a significant amount of play testing the game.
  • User Interface and Feedback: Designing an intuitive user interface that provides clear feedback to players was an essential feature of the game for me. This included displaying elapsed time, providing instructions, and ensuring that game states (such as starting or ending the game) were communicated effectively. In the end I decided to go with a very minimal layout that fits with the aesthetic of the game but I do believe that it is still intuitive and someone could understand how to play and win with minimal effort.

Final Project:
Conclusions and Reflections:
Reflecting back on this project, developing this game has been both a creative and highly technical journey.
Looking ahead, I hope to improve many aspects of this project as it is an idea that I haven’t seen before. The following are some ideas I have for future improvements to this game.
Level Design: Expanding “Going Through It” with more levels featuring diverse obstacle layouts and increasing difficulty. Moving obstacles are also a problem I hope to tackle in the future.
Multiplayer Mode: Due to the speed-run nature of the game, a mode where players can compete in real time would greatly add to the immersion and entertaining nature of the gameOverall, this project has laid a strong foundation for further development, I am genuinely excited about the game I have created and I hope to keep working on it in the future. Plus the amount of trigonometry implemented for collisions has made me a better mathematician which is always a welcome side effect.

 

MIDTERM PROJECT: SUPERMAN SAVES

INTRODUCTION

For my midterm project, I decided to build upon an earlier project concept, evolving it into a full-fledged interactive game called “Superman Saves”. This project incorporates the concepts and techniques I’ve learned in class so far.

CONCEPT

The concept of the game is simple: Superman has to rescue a person from danger by navigating obstacles such as clouds and birds. The player uses arrow keys to control Superman’s movements, helping him avoid the obstacles while trying to rescue the person in time. As the player progresses through different levels, the game increases in difficulty by speeding up the obstacles, making it more challenging to achieve the objective. 

RESOURCES

For the background image, i used DALL.E AI to generate it. I got the sounds from freesound.org

HIGHLIGHTS

One of the more challenging aspects of the project was implementing accurate collision detection between Superman and the moving obstacles (clouds and birds). The collision detection logic ensures that when Superman gets too close to an obstacle, he loses a life, and his position is reset. The difficulty lies in precisely calculating the distance between Superman and the obstacles, accounting for the different speeds and movements of the clouds and birds.

The code snippet below handles collision detection for both clouds and birds, resetting Superman’s position and decreasing his lives if a collision occurs:

function checkCollision() {
  // Check collisions with clouds
  if (dist(supermanX, supermanY, cloudX1, cloudY1) < 50 ||
      dist(supermanX, supermanY, cloudX2, cloudY2) < 50 ||
      dist(supermanX, supermanY, cloudX3, cloudY3) < 50) {
    supermanX = width / 2;
    supermanY = height - 100; // Reset Superman's position
    lives -= 1; // Lose a life
    return true;
  }

  // Check collisions with birds
  if (dist(supermanX, supermanY, birdX, birdY) < 50) {
    supermanX = width / 2;
    supermanY = height - 100; // Reset Superman's position
    lives -= 1; // Lose a life
    return true;
  }
  return false;
}

 

CHALLENGES AND IMPROVEMENTS

Creating the dynamic background and ensuring smooth movement was initially challenging. Managing multiple moving elements (clouds, birds, stars) required a balance between performance and visual appeal. Looking ahead, I plan to add more features such as power-ups for Superman, different types of obstacles, and possibly multiplayer options.

 

EMBEDDED CODE

 

 

LINK TO FULL SCREEN

 

 

Mid Term Project: Animal Sounds Trivia

CONCEPT

The game “Animal Sounds Trivia” is an interactive trivia game designed to educate players about animals. My goal is to help people identify animals by their sounds. The idea came from the realisation that, while walking in a jungle, the ability to recognise an animal by its sound could help determine whether the animal is dangerous or not.

The Game play.

The game begins with a screen containing instructions and that allow user to start the Game. The starting screen can be seen below:

From the main menu, when the player clicks a button to begin playing, the game starts. The player controls a character who walks through a forest. As the character moves forward, the distance to a destination gradually decreases (Also indicated in the progress bar).  At specific intervals (based on the distance), the player hears different animal sounds, triggering a trivia question. A pop-up window appears with multiple-choice options for identifying the animal that made the sound. The player selects an answer, and if correct, they earn 10 points for the animal. After answering, the player can continue their journey. The cycle of walking, hearing an animal sound, and answering trivia repeats until the player reaches the destination and completes the trivia challenge. Throughout the game, the background scrolls to simulate movement, and the character’s walking animation plays, giving the illusion of progress. At the end the Player is presented with their total score and can choose to restart the game.

Interesting Piece of Code

In my implementation, I added a function that type message on the screen. I find the code for the function definition interesting because of the experience it adds to the game. By typing words for instructions it adds a sense of activeness of the game.

// Function to display a typed message with a typing effect
   displayTypedMessage(x, y)
  {
    let typingSpeed = 50;  
    let lineHeight = 32;  
    let margin = 10;  
    let currentTime = millis();

    if (currentTime - lastCharTime > typingSpeed && currentCharIndex < this.instructionText.length) 
    {
      currentCharIndex++; 
      lastCharTime = currentTime;  
    }
    
// Create a substring of the instruction text to display
    let displayedText = this.instructionText.slice(0, currentCharIndex);

    let lines = [];
    let currentLine = "";
    
// Handle line breaks
    for (let i = 0; i < displayedText.length; i++) 
    {
      let nextChar = displayedText[i];
      let potentialLine = currentLine + nextChar;

// Check if the potential line exceeds the available width
      if (textWidth(potentialLine) > width*0.9 - margin * 2 - x) 
      {
        lines.push(currentLine);  
        currentLine = nextChar;   
      } else 
      {
        currentLine = potentialLine;
      }
    }
    lines.push(currentLine);  
    fill(0);
    textAlign(LEFT, TOP);
    for (let i = 0; i < lines.length; i++) 
    {
      text(lines[i], x, y + i * lineHeight);
    }

    if (currentCharIndex >= this.instructionText.length)
    {
      if (currentTime - lastCharTime > 2000) 
      {  
        currentCharIndex = 0;  
      }
    }
  }
Problems I Faced and Solutions

In the development of this game I faced several challenges. Some  of them includes the following:

  1.  Synchronising the Animal sounds so that they do not overlap: After exploring several options, I was able to solve this by  creating a function that would pause all the sounds when not in use.
  2. Managing the game Flow: This was a problem as I was designing my game, I did not have a clear structure in mind. However as I began the implementation  I was able to figure out the pieces and manage the flow smoothy.
Reflections  

As I look forward to future works, I hope to maximise the use of OOP. While I have used OOP in the implementation of my game, I think I would even use it more to create a more easily manageable code for my game than it currently is. However, I am generally proud of how the game has turned out and I look forward to having people play it.

Midterm Project – Motion Ship

#####LINK TO THE GAME#####
#####CODE OF THE GAME#####
(Unfortunately my p5 seems down for no reason;
Project is temporarily hosted on GitHub)

intro

First of all, as the game design documentation in my progress report has included the essence of my project at large, I would try to focus more on the improvements and specificities I made in this second stage of developing my NEXT-GEN-SOMATIC-MOTION-SENSING-SPACE-SHOOTING-ACTION game, Motion Ship.

tech and concept DEVELOPMENT

When it comes to the development of the project, I would say that there are two parts to the story: 1. To realize and polish my initial vision; 2. To make decisions in terms of removing elements from the plan or adding flavors to it (e.g., removing the audio level & mouse control to reduce the complexity of commands to only head motion and keyboard inputs).

1. Interactive Experience

As the centerpiece of the game, the realization of the concept of ‘controlling the spaceship with the player’s head motion’ was my primary objective. Although at the end of the first stage, I had achieved the basic mapping relationship between the head position detected by the ML model and the displayed position of the player spaceship in the game, there were still several awkward shortcomings, including:

  1. The ship respawns itself every frame in the head position directly instead of moving towards it smoothly. This was later tackled by introducing the smooth-approaching logic I used in my first project.
  2. The ship’s motion responsiveness to the head motion was too ‘authentic’, leading to the player’s having to literally move drastically in order to control the ship instead of intuitively directing the ship with slight movements. This was tackled by adding factors of motion sensitivity to the mapping relationship.
  3. The ship appeared to be ‘translating’ in space (although in terms of programming, it is), instead of reflecting the aerodynamic behavior of real aircraft. Thus, rotations in all three axes were introduced to simulate such effects.
update(headPos) {
  if (this.toDestroy === false) {
    // Update position based on head movement (-1 to 1 mapped to screen space)
    let targetX = map(headPos.x, -1, 1, -width, width);
    let targetY = map(headPos.y, -1, 1, -height * 1.5, height * 1.5);
    this.x += (targetX - this.x) * 0.15;
    this.y += (targetY - this.y) * 0.15;
    
    // Constrain the postion within the gaming zone (2.87 approx. 3 calculated from triangular perspective: fovy = 0.5, camZ = 800, shipZ = 280)
    this.x = constrain(this.x, -gamingZone.width / 3, gamingZone.width / 3);
    this.y = constrain(this.y, -gamingZone.height / 3, gamingZone.height / 3);
    
    // Update rotation based on head movement
    this.rotationX = map(-headPos.y, -1, 1, -PI / 3, PI / 3);
    this.rotationY = map(headPos.x, -1, 1, -PI / 10, PI / 10);
    this.rotationZ = map(headPos.x, -1, 1, -PI / 1.25, PI / 1.25);
    
    // Tactic engine reset
    if (this.tacticEngineOn === true) {
      let currentTime = millis();
      if (this.model === assets.models.playerShip1) {
        this.health = 100;
      } else {
        this.energy = 100;
      }
      if (currentTime - this.tacticEngineStart > 15000) {
        this.tacticEngineOn = false;
        if (this.model === assets.models.playerShip1) {
          this.health = 100;
        } else {
          this.energy = 100;
        }
      }
    }
2. Gameplay Aspect & UI

One major awkwardness I spotted then was that when the canvas aspect followed the window, the 3D spatial relationships between the objects and the visual distortion tended to be uncontrollable – for example, an enemyship could seem on the laser trajectory of the player when in the distance, but in fact it was an illusion introduced by perspectives. As a result, I devised several mechanisms to smooth out the experience, including:

  1. Define a definite gaming zone with constant aspect (1:1) on the window (regardless of whether the window is in vertical or landscape aspects).
  2. Trigonometrically calculate and confine the objects in the 3D space in relation to the camera position.
  3. Enlarge the collision box & the speed of the lasers fired to reduce difficulty when hitting moving enemies.

On top of that, other improvements besides the gaming zone include allowing enemy ships to launch lasers, incorporating different meteoroid models, displaying pilot logs and other info on the margin out of the gaming zone, displaying laser and health bar within the gaming zone, etc.

3. Visual Effects

To further improve the immersiveness of the gameplay, I made four major changes:

  1. Space dust randomly generates and flies towards the player’s ship, creating a sense of speed (compared to the insufficient indication of speed when there were only enemies and obstacles flying slowly towards the player).
    class SpaceDust {
      constructor(maxParticles = 50) {
        this.maxParticles = maxParticles;
        this.particles = [];
        this.spawnRate = 2; // Number of particles to spawn each frame
        this.initParticles();
      }
    
      // Initializes the particles array with empty particles.
      initParticles() {
        for (let i = 0; i < this.maxParticles; i++) {
          this.particles.push(this.createParticle());
        }
      }
    
      /*
      Creates a single dust particle with random properties.
      @returns {Object} A particle with position, velocity, size, and lifespan.
      */
      createParticle() {
        return {
          pos: createVector(random(-gamingZone.width / 2, gamingZone.width / 2), random(-gamingZone.height / 2, gamingZone.height / 2), -random(1000, 1500)),
          vel: createVector(0, 0, random(80, 100)), // random Z speed
          size: random(2, 4),
          lifespan: random(50, 200) // Frames the particle will live
        };
      }
    
      // Updates all particles: moves them forward and resets them if necessary.
      update() {
        for (let i = 0; i < this.maxParticles; i++) {
          let p = this.particles[i];
          p.pos.add(p.vel);
          p.lifespan --;
    
          // If the particle has passed the player or its lifespan ended, reset it
          if (p.pos.z > 300 || p.lifespan <= 0) {
            this.particles[i] = this.createParticle();
          }
        }
      }
    
       // Renders all particles onto the screen.
      render() {
        push();
        // Enable additive blending for a glowing effect
        blendMode(ADD);
        for (let p of this.particles) {
          push();
          translate(p.pos.x, p.pos.y, p.pos.z);
          noStroke();
          fill(255, 255, 255, map(p.lifespan, 0, 200, 50, 255)); // Fade out based on lifespan
          sphere(p.size);
          pop();
        }
        blendMode(BLEND); // Reset to default blending
        pop();
      }
    }
  2. Vignette effect in the background to create depth instead of having all the objects floating on a plane.
    loadBackgroundWithVignette(key, path) {
      loadImage(path, (img) => {
        const vignettedImg = this.applyVignette(img);
        this.textures[key] = vignettedImg;
      });
    }
    
    applyVignette(img) {
      // Create a graphics buffer the same size as the image
      let gfx = createGraphics(img.width, img.height);
      gfx.clear();
    
      // Parameters for the vignette
      let centerX = img.width / 2;
      let centerY = img.height / 2;
      let maxDiameter = max(img.width, img.height) * 1.25;
    
      gfx.noFill();
      gfx.background(0, 0, 0, 0); // Ensure transparency
    
      gfx.blendMode(BLEND);
    
      // Draw multiple concentric ellipses to create a radial gradient
      for (let r = maxDiameter / 2; r > 0; r -= 20) {
        // Adjust alpha based on radius
        let alpha = map(r, 0, maxDiameter / 2, 40, 0); // intensity: darkest part = 50, larger the darker
        gfx.noStroke();
        gfx.fill(0, 0, 0, alpha);
        gfx.ellipse(centerX, centerY, r, r);
      }
    
      // Convert gfx (p5.Graphics) to p5.Image
      let vignetteImage = gfx.get();
    
      // Create a copy of the original image to avoid modifying it directly
      let processedImg = img.get();
    
      // Blend the vignette image onto the processed image using MULTIPLY mode
      processedImg.blend(vignetteImage, 0, 0, vignetteImage.width, vignetteImage.height, 0, 0, processedImg.width, processedImg.height, MULTIPLY);
    
      return processedImg;
    }
  3. Parallax effect of the background to increase the responsiveness of environment to the player’s motion.
    class Background {
      constructor(texture) {
        this.texture = texture;
        this.xOffset = 0;
        this.yOffset = 0;
        this.playerPreviousX = null;
        this.playerPreviousY = null;
        this.parallaxFactor = 250; // Adjust for parallax strength
      }
    
      update(playerX, playerY) {
        let playerMovementX = playerX - this.playerPreviousX;
        let playerMovementY = playerY - this.playerPreviousY;
        
        // Calculate the background offset
        this.xOffset += playerMovementX * this.parallaxFactor;
        this.yOffset += playerMovementY * this.parallaxFactor;
        
        this.playerPreviousX = playerX;
        this.playerPreviousY = playerY; 
      }
    
      render() {
        push();
        translate(-this.xOffset, -this.yOffset, -5000); // Positioned far in the background
        noStroke();
        texture(this.texture);
        // Render a large plane to cover the background area
        plane(width * 7.5, height * 7.5);
        pop();
      }
    }
  4. The windshield (although only frames) around the gaming zone to enhance the sense of an FPP piloting experience.

4. Game Flow

After hearing feedback from several friends, I decided to add an instruction page before entering the gameplay to make life easier for the players.

In addition, I also enabled the player to restart the game immediately instead of having to restart from scratch or reconfigure the game.

5. Storytelling

Last but not least, one of the most illuminating takeaways from developing this project is to recognize and accommodate the gap between a developer’s understanding/assumption and the players’ ‘infinite’ possibilities to approach the product. For example, displaying the variable names on the screen or using them in the instructions seems to be clear enough for me during the development, while a player may not have enough experience or interest to distinguish and follow.

Therefore, I replaced the variable names with terms of more meaning within the space action worldview to create more intuitive guidelines for the player with the aid of visual indications.

SOme words, in hindsight

It is true that there is no ‘perfection’ in terms of finishing a project – at this point, I still have many ideas to add to the game if regarding it as a game to publish or so, including level design, more value balance, more storytelling, enemy and obstacle varieties, bosses, more tactic engines (special skills of each ship), more consistent aesthetics, and so on. On the other hand, I found myself quite satisfied with this current presentation – in terms of me utilizing wheels and knowledge learned in the process, trying to think not only from a developer perspective, and establishing a coherent storytelling through a product, etc. And it made me more excited to get into the physical programming.

Midterm Project – Winter Wonderland

As I have mentioned in my Midterm Progress Report, my goal was to create not just a game, but rather an interactive environment for which I took inspiration from the game I played a long time ago with my friends.

Fortnite Winterfest Presents - How to Get Free Daily Gifts

It was a long journey from the beginning to the end of my work that included not much but, still, some challenging parts that I will describe later in this blogpost.

Concept

Initially, I wanted to create an interactive game related to Christmas Eve, and simply work on good-quality visuals and add certain interactions, e.g. opening the gifts. However, after getting feedback from the professor and thinking about other potential ideas, I realized that it would not be enough for me to be fully satisfied with the results. That is why I decided to add the game that would also include good-quality animations and sprites, and would incorporate the collision detection and OOP principles.

As it needed to also be related to Christmas, I decided to make the Santa the main character of the game. Initially, I wanted to do something with the landscape orientation as my game is pretty wide. However, I decided to reject that idea because of the potential problems with the screen movement control. (For my laptop, for example, as it has a small screen, the game exceeds the boundaries of the monitor, so I need to scroll through the screen).

I decided to implement the game with the basic concept of ‘something falling from the sky, and you either need to dodge it or catch it’. Nothing special, but I strived to make it as fun as possible. In my game, the background poster inside the house tells that there is a shortage of gifts. The goal of the user is to help Santa to catch the gifts while dodging the icicles falling from the sky. The user can control the character by using the arrow keys.

Talking about the broader picture outside of the mini-game that I just described, my game consists of two main stages, outside the house (serves mainly aesthetic purposes with very nice background music that I received multiple compliments about haha), and inside the house (platform for interactions and ‘entrance’ to the mini-game).

PLAY THE GAME IN THE FULLSCREEN (PRESS ‘F’ FOR THE FULL FULLSCREEN)

Problems and Solutions

Although there were not too many problems, there were enough difficulties and struggles that it will not be possible to fit here, so I will focus mainly on those that I’m actually proud of resolving.

1) By my mistake, the biggest struggle was to connect the games together. Yes, you read it right. Connect the games.

For some reason, I was naive enough to think that p5.js has a function that can magically embed one sketch into another. Don’t get me wrong, p5.js is an amazing platform with many functionality and features to offer, but I expected such a concept of unification to exist. Exactly why, I decided, to make things easier and write the code for my mini-game in the separate file. It was to my big surprise to realize, after an hour of trying, that it is impossible to just straight up integrate the mini-game into my main file. So I needed to put a lot of work and precision into the transfer of the code, and, at some points, to hardcode, to plug the mini-game into the screen of the main game as you can see playing it now.

} else if (currentScene === 4) {
  // Game scene
  playGameSceneMusic();
  image(blurred_house_interior, 0, 0, 1800, 900);
  fill(0, 147, 255);
  rect((width - sceneGameWidth) / 2, (height - sceneGameHeight) / 2, sceneGameWidth, sceneGameHeight); 
  
  isMouseOnArrow = checkIfMouseOnArrow();
  drawArrow(); // to be able to exit back to scene 2
  
  if (!gameStarted) {
    displayRulesScreen();  // rules
  } else if (gameOver) {
    displayGameOverScreen(); //game over
  } else if (gameWon) {
    displayWinScreen(); // win
  } else {
    playGame(); // game state

2) Music and Sound effects were not behaving as intended. The main problem was the repetitiveness and infinite looping of the sounds during the interactions with the object. For example, a knock on the door would repeat itself from the start to the finish all the time while the mouse is pointing at it. I needed to fix it using the limiting boolean conditions (true/false). I hope you get what I mean by this. If you don’t, perhaps it will be easier when you’ll look into the code.

if (mouseX > doorX && mouseX < doorX + doorWidth && mouseY > doorY && mouseY < doorY + doorHeight) {
  doorTrigger = true;
  
  if (doorKnockCharged === true) { // to play sound once per mouse pointing 
    doorKnock.play(); 
    doorKnockCharged = false;
  }
} else {
  doorTrigger = false; 
  doorKnockCharged = true; 
}

3) Screen scrolling with the arrow keys did not allow to make the experience of playing the mini-game enjoyable. The Santa movements are bonded to the Left Arrow and Right Arrow. At the same time, as I have mentioned above, my screen, as I expect to be for most users as well, was too short, so the picture of the game is scrollable in the fullscreen mode. In p5.js, arrow keys trigger the screen scrolling, which interrupted the mini-game flow as the screen waas constantly moving left and right with the key clicks. I even posted the question in the discord channel, but after the internet research I found the solution.

// blocking arrow key default behavior using window event listener
window.addEventListener("keydown", function(event) {
  if (event.key === "ArrowUp" || event.key === "ArrowDown" || event.key === "ArrowLeft" || event.key === "ArrowRight") {
    event.preventDefault();  // Prevent default scrolling behavior
  }
});

 

4) When opening the gifts and the mini-game, I needed to come up with the background to be used. As looking for new backgrounds would take too much time, I decided to make it in a similar way many games do – blur the background to make the effect of focus on the chosen item. Initially, I tried to implement it using the filter(BLUR, ...) function in p5.js. Although the effect looked nice, for some reason, my game started lagging and freezing during the scenes with using the blur (probably has something to do with the constant update of pixels on the screen). So I decided to make a little smart move – instead of blurring the picture inside the game, I blurred the picture using the blurring tool on the internet and simply plugged it into my sketch.

PLAY THE GAME IN THE FULLSCREEN (PRESS ‘F’ FOR THE FULL FULLSCREEN)

Conclusion

I am very proud of my work on this midterm project. I accomplished more than I initially planned to, and I managed to maintain a more or less high standard of gaming. I found good quality images, sounds, and sprites, I successfully handled the unexpected difficulties, and managed to build the game without significant bugs (hopefully there are no bugs at all haha). Most importantly, I achieved my initial goal of creating an art piece of nostalgia for myself, and I did it by putting in a lot of hard work and thinking processes. Of course, there are a lot of things that I could add to the game or implement in a better way, for example using less hardcoding and following a more logical and organized approach. I could make more high-level effects or create better-quality textures, etc.. Unfortunately, it was not enough time to accomplish all that I could.

Nevertheless, I am happy with how the course is going so far. I have a lot to learn and grasp, and it keeps me excited and motivated for the second half of the course. Looking forward to working with Arduino!

Midterm Project – ICEY IMPACT


Concept:

The game is an arena-style, two-player game where each player controls a snowball. The goal is to either knock the opponent’s snowball (represented by an emoji image) out of the arena or collect three coins. Which ever player gets to three points first wins. A scoreboard is displayed on screen to show each player’s current score and coin count.

Sketch:
User Interaction: 
  • The game begins with an instruction screen, requiring user input to proceed.
  • Player 1 controls their snowball using the WASD keys, while Player 2 uses the arrow keys.
  • Players navigate the arena, collecting coins or attempting to knock their opponent out of bounds.
  • The first player to collect three coins or knock their opponent out three times wins.
  • Players can choose to start a new session after completing the game.
    Implementation: 
  • The game has several classes, each of which contributes to different aspects of the experience:

    • Game: This class manages the overall state of the game, including showing screens, handling instructions, tracking game progress, and determining when a round or the game ends.
    • Player: The Player class handles all of the attributes and behavior of each player. This includes movement (based on keyboard input), collision detection, score tracking, and boundary constraints.
    • Arena: The Arena class defines the boundary within which players compete. It is used to detect if a player has fallen out of bounds.
    • Item: The Item class is used to create collectible items (coins). When a player collects an item, it increases their coin count.

    Key features incorporated into the game:

    • Object-Oriented Programming: The game is structured using classes such as Game, Player, Arena, and Item to ensure modular and reusable code.
    • Visuals: The game uses images for players, the background, and items (coins).
    • Sound: Sounds are used for collecting coins and when the game ends.
    • User Input: Player controls are managed using keyboard inputs (WASD and arrow keys).
    • Collision and Boundary Detection: Players can collide with each other, and boundary detection is used to check if players fall out of the arena.
      Key Challenges Faced: 

      One of the primary challenges faced during development was handling the collision physics between the players. The snowball collisions had to feel dynamic, but it was difficult to achieve perfect elasticity. The physics calculations were complex, especially considering that each player’s position and velocity had to be updated to reflect an elastic collision.

      Another challenge was optimizing the game so that it could run smoothly in p5.js. Initially, I wanted to incorporate more images and sounds, but p5.js struggled to handle all of the resources, leading to long loading times. Ultimately, I had to simplify the assets to ensure smooth gameplay.

Code That I Am Proud Of: 

I am particularly proud of the resolveCollision() function in the Player class, which handles the collision between players. The function calculates the angle and then applies new velocities to the players to simulate the effect of a collision. This code makes the game feel more dynamic and fun, as players can push each other around the arena.

resolveCollision(other) {
  let dx = other.x - this.x;
  let dy = other.y - this.y;
  let distance = Math.sqrt(dx * dx + dy * dy);

  if (distance < this.radius + other.radius) {
    let angle = Math.atan2(dy, dx);
    let v1 = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
    let v2 = Math.sqrt(other.vx * other.vx + other.vy * other.vy);

    let newVx1 = v2 * Math.cos(angle);
    let newVy1 = v2 * Math.sin(angle);
    let newVx2 = v1 * Math.cos(angle);
    let newVy2 = v1 * Math.sin(angle);

    this.vx = newVx1;
    this.vy = newVy1;
    other.vx = newVx2;
    other.vy = newVy2;

    let overlap = (this.radius + other.radius) - distance;
    let moveX = overlap * Math.cos(angle) / 2;
    let moveY = overlap * Math.sin(angle) / 2;
    this.x = this.x - moveX;
    this.y = this.y -moveY;
    other.x = other.x + moveX;
    other.y = other.y + moveY;
  }
}

This function might not achieve perfect elasticity, but it gives a satisfying collision effect, enhancing the overall player experience.

Reflection: 

Looking back, I am mostly satisfied with how the project turned out, especially given the challenges with collision detection and resource optimization. One thing I wish I could improve is the collision physics—ideally, the collisions would be perfectly elastic, allowing for even more realistic interactions between the players. However, achieving this in a way that felt right with p5.js was more challenging than expected. Despite these challenges, the game is enjoyable and provides a satisfying experience for both players.

Midterm – Interactive Zoo

Concept

I created an interactive zoo-themed game where players get to dive into the fun of feeding different animals. The game features a variety of enclosures, each housing unique animals like a Lion, Elephant, Giraffe, and Bear, along with their distinctive images and sounds. The main goal is to correctly feed each animal their preferred food while managing a limited number of attempts. It’s all about exploring the zoo, having fun, and seeing how well you can feed the animals! The gameplay is designed to be engaging and straightforward. Players drag and drop food items into the enclosures, trying to match the right food with the right animal. It’s a lively experience that captures the excitement of a day at the zoo while keeping players entertained and challenged.

What I’m proud of the most is how the zoo home looks like:

Code Snippets

I’m proud of the code for the feedback system; it plays distinct sounds for correct and incorrect food choices, while also displaying visual messages. This helps the player learn from their mistakes in real time.

checkFood(chosenFood) {
  if (chosenFood.name === this.correctFood) {
    correctSound.play(); // Play the correct sound if food is right
    correctFeeds++; // Increment correct feeds count
    gameWon = (correctFeeds === zoo.length); // Check if all animals have been fed correctly
    showCorrectMessage = true; // Show correct message

    // Stop the sound for the current enclosure
    for (let enclosure of zoo) {
      if (enclosure.name === currentEnclosure) {
        enclosure.stopSound();
      }
    }
  } 
    else {
    wrongSound.play(); // Play the wrong sound if food is wrong
    lives--; // Decrement lives
    
    // Check for loss condition
    if (lives <= 0) {
      gameOver = true; // Set gameOver to true if lives reach zero
    }
  }
 }

Another code snippet I’m proud of is the mousePressed function because it lets the player easily move from the instruction screen to exploring the zoo, and if they win or lose, it resets everything for a fresh start. The way it checks if an enclosure was clicked and responds to player actions keeps the gameplay fluid and intuitive, making it simple for anyone to jump in and play without getting stuck.

function mousePressed() {
  if (instructionScreen) {
    instructionScreen = false; // Exit instruction screen when clicked
  } else if (gameOver || gameWon) {
    // Reset game state and go to instruction screen
    lives = 3;
    correctFeeds = 0; // Reset correct feeds count
    gameOver = false;
    gameWon = false;
    instructionScreen = true; // Reset to instruction screen
    currentEnclosure = null;
    for (let enclosure of zoo) {
      enclosure.stopSound();
    }
  } else if (currentEnclosure === null) {
    // Check if an enclosure is clicked
    for (let enclosure of zoo) {
      enclosure.checkClick();
    }
  } else {
    // Reset showCorrectMessage for the next animal
    showCorrectMessage = false;
  }

The Good Parts

The game runs on a combination of object-oriented programming and easy-to-understand mechanics. Each animal enclosure is an instance of the Enclosure class, complete with its own attributes like size, name, images, sounds, and the specific food it needs. Players simply drag and drop food items into the right enclosures, and the game gives instant feedback on whether they made the correct choice or not.

I’m really proud of how I integrated audio into the game. Each time players make a correct or incorrect choice, they hear distinct sound effects that add a fun layer to the experience. Plus, I included on-screen messages that help players understand what they did right or wrong, making it easy to learn and improve. I also love how the design encourages players to explore different enclosures and challenges, creating a loop of fun that keeps them engaged. The restart feature is a nice touch too, allowing players to jump right back in if they want to try again after finishing a round.

The Not So Good Parts

Even though I’m happy with how the project turned out, there are definitely areas where I could improve. For instance, the user interface could use a bit more flair to make it visually appealing. Sprucing up the background and button designs would enhance the overall experience. I also want to fine-tune the drag-and-drop mechanics to make them even smoother, as some players might find it tricky to place the food just right.

During the development process, I faced a few challenges along the way. One significant issue is that there are still some bugs that I didn’t have time to fix. For example, players can exploit a loophole where feeding the same animal the correct food four times counts as a win, which isn’t the intended gameplay experience. Additionally, if players don’t drag the incorrect food item away before placing the correct one, both the correct and wrong sounds will play simultaneously, which can be confusing. I also noticed that the food items tend to stick together when they touch, almost like magnets, which adds an unintended dynamic to the dragging mechanic. However, when players switch to another enclosure, the food items reset as intended, which is a positive aspect. These challenges highlighted the importance of thorough testing and debugging, and I plan to address them in future iterations of the game.

Midterm Project – Moves

Game Design

After receiving feedback and asking my friends to play through the game draft, I made some changes to the original game design:

  • Player control: Instead of mouse movement  + keyboard movement, I decided to use full keyboard movement.
  • Implementing two different obstacles instead of one: rock and destroyable dancing keys.
  • I initially plan to make the game full screen, however, the player movement will then be too wide and decrease the difficulty of the game when the character moves around to avoid asteroids.

End game and winning mechanism: a progress bar to track how many obstacles the player has destroyed. If player manages to stay alive and fill the whole progress bar, they win. Else if player used of all of their lives, they lose. I also give the player 9 lives as a reference to the saying “cats have 9 lives”.

The player lose lives when: got hit by asteroids, miss a key or press the wrong key.

Story

I am particularly proud of the story and implementation of arts in this game. I have experience with coding before, so I decided that for this project in IM I want to make the game more conceptual and tell a comprehensive story.

I draw a few scenes at the start of the game to create a storyline for the cat hero. The story is about a normal cat who enjoys music but one day a extraterrestrial comet hit the Earth and gave him superpower that can be unlocked with his dance moves. With great power came great responsibility, he has to use his power to protect the Earth from alien invasion.

All of the arts in this game or created by me except for the background photo, the asteroid and the heart in the winning screen.

Main character – cat hero drawn by me with background photo generated by AI

Final game (size 400×400)

Struggles

The main struggle I have was with the game design. I was basing my game on normal dancing game, for example, Just Dance now. However, there are some factors I want to change, mainly the movement left and right of the character, hence, the same game mechanism does not work very well for my game. After the first game demo, I realized what was missing from my game was response to the player interaction. For example, key disappearing or asteroid disappearing when interacting with users. In the final, I make the asteroid disappear after hitting the cat and implement a progress track bar for the scores. However, if I have more time to work on this project in the future, I would implement sound response or visual cue like displaying the key user just pressed or signs when user loses live.

Reflection

Making game has always interested me before and I really enjoyed making this midterm project, especially the story telling part. Some particular part I identified to improve in the future are sound design and visual design. Some feedback I received from my friend also help me think about the game design. For example, a feedback I received was how the asteroids were coming towards the Earth and the cat was avoiding it instead of destroying it, which clash with the storyline. I think it’s a good observation that I did not realize when creating the game.

Midterm Project: Groovy Derby

Groovy Derby: Link To Fullscreen

Groovy Derby: Link To P5

Concept:

The concept for my project was inspired by the co-op game It Takes Two, where two game characters set out on a journey that is filled with cooperative minigames and obstacles which they have to overcome. As such, I wanted to create a minigame where the game is only “playable” if two people are communicating and working together. Combining with themes from arcade games such as a limited number of lives and endless generative spites, I created Groovy Derby where two players have to input the correct order of key combinations in order to score points in the game.

Project Workings:

For my project, I am extremely happy with the character design and the way that they move and interact with each other. Although they don’t move from their position, the way the characters match each other movements in almost an animated way had relived me of a lot of stress. Particularly because I was really worried, I wouldn’t be able to have the characters move in a certain way and the game would look super chunky/ blocky. I think looking at animations and working frame-by-frame really helped my character movements, and in the end I had 5 frames/ designs for the characters to move. If there is anyone looking for “animated” characters, I recommend breaking down the movement into pieces and seeing how they would look on screen.

On the technical end, I am happy with the game mechanics and interactions between the user input with the creatures. I also really worried on how to connect the key pressed and possible decrement of the combination from the creature encroaching onto the characters. For that, I created player and creature class methods that checked the first combination with the input of the user, and if it matched, then the first combination would be removed. If it was the wrong input, the creature would keep moving towards the center, and if it reached a certain range within the players, a life would be lost.

As for improvement on the code, I believe the code can be more optimized as some parts were copied pasted, then the variable was changed to match what I was trying to do. I wish there were more randomization in the code because after round 6, there is a 1/3 chance for any of the creatures to be loaded in. On the game design part, I wish there were more user feedback such as when a life is lost, when a button is pressed, when the game is starting, additional sound effects, etc,. However, given we had ~1.5 to 2 weeks to complete this project, I am happy with the end result and progress that I was able to implement into my project.

Player Class
let playerHead = width / 33; // ~50 pixels
let distanceApart = width/ 26 // ~65 pixels
let player1 = new playerCharacters(player1Color, distanceApart, 0, playerHead);
let player2 = new playerCharacters(player2Color, -distanceApart, 0, playerHead);

player1.player1Moves();
player2.player2Moves();
player1.playerHitBox(player2);

Final recommendations for people on a time crunch, but want their design to look nice, I had used Canva to design a lot of my background and additional image/text that didn’t need to move. For the game sounds, I went to a free sound effect website and download clips, then looped it in p5. For custom fonts, I went to a free custom fonts website and make sure to have a .ttf file or it might not work as intended. Last, I want to mention that the heart design was generated was AI generated because I couldn’t determine the vectors/ shapes needed for my design.