Week 8 Reading

Reading Norman’s Emotion & Design: Attractive Things Work Better made me think about how much our emotions influence not only our experience with products but also our perception of their effectiveness. I have always been drawn to minimalist and aesthetically pleasing designs, but I never consciously considered that the way something looks could actually change how well it functions in my mind. Norman’s argument that attractive things put us in a positive emotional state, which then makes us more creative and tolerant of problems, really resonated with me. It reminds me of how I feel when I use a well-designed app: if the interface is clean and straightforward, I naturally assume it’s easier to use, even before I’ve tested its features. When choosing basic necessity goods at the store, I tend to lean towards those with an aesthetically appealing package.  It also made me reflect on branding strategies I’ve worked on in the past, where visual identity is not just about aesthetics but about making the user feel like they resonate with the brand’s values enough to engage more deeply.

Similarly, Her Code Got Humans on the Moon was a fascinating look at Margaret Hamilton’s contributions to the Apollo program, and it left me thinking about the intersection of creativity and logic in problem-solving. Her story challenged the way I usually imagine coding (often as monotonous and technical) by showing how she had to anticipate every possible mistake and failure scenario. I was especially struck by how she fought for software engineering to be recognized as a legitimate discipline. It made me wonder how many fields today are still in that stage, where groundbreaking work is being done but isn’t yet fully acknowledged. In a way, it reminds me of digital community-building and brand storytelling, which are the areas I work in that are often undervalued despite their fundamental importance.

Both readings reinforced something I’ve been thinking about a lot: creativity isn’t just for traditional “creative” roles. Whether in design, engineering, or strategy, thinking outside the box is what pushes boundaries and leads us to creating great things.

Midterm Project

Link to the Sketch: https://editor.p5js.org/izza.t/full/V9Mv_WERI

For my midterm, I decided to do a spin-off of a classic maze that is also heavily inspired by 2 other things I love: mystery and cats. The story of the game involves an archeologist exploring an abandoned tomb that is said to hold a large treasure with their cat. Suddenly, something spooks the cats and it runs off into the tomb. It is then revealed that the tomb is like a maze, and the user must navigate through it. The catch? It’s pitch black apart from the small light from their flashlight and there are booby traps in certain parts of the maze like a mummy, beetles, and a snake that will cause the player to have to restart if the player collides into them.

The game works by showing a start screen that explains the situation and what keys to use to navigate the game. The player uses the arrow keys to navigate up, down, left, and right through the maze and can use the ‘C’ key to call for their cat and hear it’s meow which expands their flashlight radius momentarily (almost like a power up). This feature does have a cooldown feature that is displayed at the top. The user must navigate through the maze to the end to win and find both their cat and the lost treasure. They must do so without triggering any of the booby traps and dealing with all of the dead ends in the maze.

The maze itself took the longest time to create, almost an entire day, as it all had to be hardcoded using an image I had found of tomb-like stone walls online. Then, creating the flashlight like circle around the player and making sure that only pieces of the maze that are within that circle are displayed required the use of masking. This required me to use a new function called drawingContext which unlocks more features of the canvas in p5js and allowed me to do that. The code for which I’m very proud of and can be seen below.

class Maze {
  constructor() {
    this.walls = [
      // Outer boundaries (these are always visible)
      {x: 75,    y: 0,    w: 1200, h: 30},   // Top
      {x: 0,    y: 570,  w: 1200, h: 30},   // Bottom
      {x: 0,    y: 0,    w: 30,    h: 600}, // Left
      {x: 970, y: 0,    w: 30,    h: 535}, // Right

      // Interior walls (these are only visible within the flashlight radius)
      {x: 75,  y: 25,  w: 10,   h: 100},
      {x: 75,  y: 165,  w: 10,   h: 220},
      {x: 75,  y: 425,  w: 10,   h: 90},
      {x: 145,  y: 25,  w: 10,   h: 100},
      {x: 195,  y: 25,  w: 10,   h: 100},
      {x: 195,  y: 115,  w: 75,  h: 10},
      {x: 75,  y: 115,  w: 75,  h: 10},
      {x: 75,  y: 165,  w: 200,  h: 10},
      {x: 265,  y:115,  w: 10,   h: 55},
      {x: 75,  y: 375,  w: 165,  h: 10},
      {x: 75,  y: 425,  w: 215,  h: 10},
      {x: 280,  y: 295,  w: 10,   h: 140},
      {x: 235,  y: 355,  w: 10,   h: 30},
      {x: 105,  y: 345,  w: 140,  h: 10},
      {x: 155,  y: 295,  w: 135,  h: 10},
      {x: 155,  y: 255,  w: 10,   h: 50},
      {x: 105,  y: 205,  w: 10,   h: 150},
      {x: 75,  y: 515,  w: 210,  h: 10},
      {x: 280,  y: 515,  w: 10,  h: 60},
      {x: 105,  y: 490,  w: 205,  h: 10},
      {x: 105,  y: 450,  w: 205,  h: 10},
      {x: 105,  y: 450,  w: 10,  h: 50},
      {x: 155,  y: 255,  w: 155,   h: 10},
      {x: 115,  y: 205,  w: 195,   h: 10},
      {x: 300,  y:95,  w: 10,   h: 115},
      {x: 235,  y: 85,  w: 75,  h: 10},
      {x: 300,  y:255,  w: 10,   h: 205},
      {x: 300,  y:490,  w: 10,   h: 85},
      {x: 225,  y: 25,  w: 10,   h: 70},
      {x: 345,  y: 25,  w: 10,   h: 320},
      {x: 345,  y: 345,  w: 225,   h: 10},
      {x: 345,  y: 395,  w: 60,   h: 10},
      {x: 465,  y: 395,  w: 60,   h: 10},
      {x: 345,  y: 395,  w: 10,   h: 180},
      {x: 515,  y: 395,  w: 10,   h: 180},
      {x: 565,  y: 345,  w: 10,   h: 180},
      {x: 565,  y: 525,  w: 50,   h: 10},
      {x: 605,  y: 300,  w: 10,   h: 230},
      {x: 655,  y: 165,  w: 10,   h: 410},
      {x: 405,  y: 300,  w: 205,   h: 10},
      {x: 405,  y: 255,  w: 205,   h: 10},
      {x: 405,  y: 225,  w: 205,   h: 10},
      {x: 605,  y: 225,  w: 10,   h: 40},
      {x: 405,  y: 255,  w: 10,   h: 50},
      {x: 405,  y: 25,  w: 10,   h: 210},
      {x: 465,  y: 165,  w: 195,   h: 10},
      {x: 465,  y: 85,  w: 10,   h: 90},
      {x: 465,  y: 85,  w: 225,   h: 10},
      {x: 685,  y: 85,  w: 10,   h: 25},
      {x: 685,  y: 150,  w: 10,   h: 425},
      {x: 745,  y: 20,  w: 10,   h: 345},
      {x: 745,  y: 410,  w: 10,   h: 120},
      {x: 745,  y: 525,  w: 70,   h: 10},
      {x: 805,  y: 450,  w: 10,   h: 85},
      {x: 865,  y: 450,  w: 10,   h: 85},
      {x: 805,  y: 445,  w: 70,   h: 10},
      {x: 865,  y: 525,  w: 140,   h: 10},
      {x: 745,  y: 410,  w: 145,   h: 10},
      {x: 935,  y: 410,  w: 40,   h: 10},
      {x: 745,  y: 355,  w: 170,   h: 10},
      {x: 905,  y: 90,  w: 10,   h: 275},
      {x: 845,  y: 90,  w: 60,   h: 10},
      {x: 845,  y: 90,  w: 10,   h: 245},
      {x: 785,  y: 20,  w: 10,   h: 315},
      {x: 785,  y: 325,  w: 60,   h: 10},
    ];
  }

  display() {
    for (let i = 0; i < 4; i++) {
      let wall = this.walls[i];
      image(stoneWall, wall.x, wall.y, wall.w, wall.h);
    }

//creating the masking
    for (let i = 4; i < this.walls.length; i++) {
      let wall = this.walls[i];
      // Create a mask for the wall
      drawingContext.save();
      drawingContext.beginPath();
      drawingContext.arc(player.x, player.y, lightRadius, 0, TWO_PI);
      drawingContext.clip();
      image(stoneWall, wall.x, wall.y, wall.w, wall.h);

      drawingContext.restore();
    }
  }

The outline of the maze itself can be seen in this image below which I took before I made the maze pitch black apart from the flashlight.

The flashlight itself is another thing I am very proud of as I wanted to make it look as natural as the way the light coming from a flashlight looks like. This means it has a bright center and a smooth gradient to transparent. For this effect, I had to learn how to use the blendMode in p5js which allowed me to create it in the easiest way. The code for this can be seen below.

function drawFlashlight() {
  fill(0);
  noStroke();
  rect(0, 0, width, height);

  blendMode(SCREEN); 
  drawingContext.globalCompositeOperation = 'lighter'; 

  // Draw the flashlight gradient
  let gradient = drawingContext.createRadialGradient(
    player.x, player.y, lightRadius / 4,
    player.x, player.y, lightRadius 
  );
  gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
  gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); 
  drawingContext.fillStyle = gradient;
  drawingContext.beginPath();
  drawingContext.arc(player.x, player.y, lightRadius, 0, TWO_PI);
  drawingContext.fill();
  blendMode(BLEND);
}

The result of this and the masking can be seen in the image below (with a peep of one the traps – the mummy):

The game proved to be more challenging than I anticipated, and I quickly realized I had set the bar a little to high for myself. Originally, I wanted the player to be a sprite of an archeologist and to have all the booby traps be animated and moving. However, with time constraints and animation struggles, I wasn’t able to do that (but would love to try and incorporate in the future). I also wanted for the cat to somehow appear at the edge of the flashlight’s radius when the ‘C’ key was pressed, the radius of the flashlight expanded, and the meow sound occurred.

Overall, I am still very proud of the game I ended up creating. It is fun, has an overarching Egyptian theme through carefully selected images and even the Papyrus font, and has a niche to it that sets it apart from other games. I learned a lot about p5js and how to code new things while working on this game, and I hope you enjoy playing it!

Week 6 – Midterm Project

1. p5js Sketch

If the experience looks static, please click on the ‘sketch’ version and run it. If you do not see the sketch to the entire width and height, please use the ‘sketch’ version instead.

2. Overall Concept

In my midterm project, the user takes on the role of a beta-tester of a 2D RPG casual adventure game “Tales of Avella” played on a fictional, futuristic ‘Playstation 9’ device. ‘Playstation 9’ is meant to be a much more state-of-the-art video game console than the currently available ‘Playstation 5’ (see Fig. 1). In “Tales of Avella,” the user has the opportunity to explore the world and help someone in need. Upon beginning the experience, the Playstation 9 apparently “turns on” and “loads” the game. The user is greeted with a welcome message from fictional PixelBloom Studios developers, as well as informed with background story for the game and instructions for controlling the user’s character, “Luke.” The background story of the game goes as follows: Luke has just moved into the charming village of Avella and is ready to discover what makes this town so special. The user can control “Luke” to explore the world in “Tales of Avella.” using the arrow keys (left, right, up, down). Depending on the user’s actions, the user could enter new areas and meet a non-playable character (NPC) farmer with a quest to harvest forty-five carrots. Upon completion of the quest, a congratulatory message is displayed, followed by a ‘memory’ snapshot of a gratitude dinner with the farmer and his daughter Lily is displayed. Finally, the user faces an option to restart the game, by pressing ‘Y’ for yes and ‘N’ for no.

Playstation 5 - Photo by Ben Iwara (https://unsplash.com/photos/white-printer-paper-on-brown-wooden-table-tnfbre82_hc)
Playstation 5 – Photo by Ben Iwara (https://unsplash.com/photos/white-printer-paper-on-brown-wooden-table-tnfbre82_hc)
Playing the PlayStation 5, Photo by Yan Krukau: (https://www.pexels.com/photo/close-up-shot-of-person-holding-a-game-controller-9069305/)
Playing the PlayStation 5, Photo by Yan Krukau: (https://www.pexels.com/photo/close-up-shot-of-person-holding-a-game-controller-9069305/)

The user has the opportunity to interact with the world in ways more than moving Luke around. The user could use mouse clicks to progress through the conversation between the farmer and Luke. At some point in the conversation, and if the user decides to accept the farmer’s quest, the farmer’s name is revealed from an initially mysterious title “???”. The user could have Luke grab a tool in Luke’s vicinity by pressing ‘i’. The user could also have a shovel-handling Luke harvest some carrots by pressing ‘i’ and replant some carrots by pressing ‘r.’

3. How Project Works & Good Parts

Good, major game design aspects can be found in project concept, project structure, dialogue flowchart, assets (video, image, audio), character design, story design, quest progress possibilities, quest progress feedback, as well as particular details of the game mechanics. Firstly, the project concept is an attempt on an innovative twist on a simply general game played on a browser on the PC – by simulating the experience of playing a game on a futuristic device, and creating a story for the user as a beta-tester of a game. Thus, there is a frame narrative entailing a story within a story; the character “Luke” within the game “Tales of Avella” has a story that can be played by a “beta-tester” that has a story in supporting the developers at a fictional PixelBloom Studios Inc. The juxtaposition of a pixelated game played in a futuristic device is another game design choice with the intention of bringing an interesting effect – whether it is raising questions, emphasizing contrast in technological development vs historical game interest, or something else. Second, the project has been structured in six stages from 0-5, namely: (0) Opening with Background Story and Instructions; (1) Game Landing Scene (Inside Luke’s House); (2) Game Scene 2 – Luke’s Neighbourhood Outside His House; (3) Game Scene 3 – Farm; (4) Game Scene 4 – Inside Farm Shed; (5) Quest Completion Congratulatory Message with Dinner Memory Fragment and Option to Restart. A gallery containing snapshots of the game progress may be seen below. Third, considering the complex nature of a dialogue between a quest-giving farmer and Luke, I decided to create a flowchart (see flowchart image below the gallery). Fourth, videos were personally designed through Canva, taking into consideration adherence to the concept of the futuristic device interface and visual appeal through positioning of text, etc. I also browsed through audio, considering its appropriateness to the scene at hand; ambient music when the Playstation 9 opens up, relaxing acoustic guitar for the dinner memory, and game atmosphere sounds based on my past experience with Playstation 4/5. Character spritesheets were taken from Spriter’s Resource, chosen based on their closeness to the ideas of the characters I had in mind: a young adult entering a new town and a farmer. Fifth, I spent time on character design (see character traits table below flowchart). Sixth, I designed the message from Pixelbloom Studios Team to the player. Seventh, quest progress possibilities were considered and quest progress feedback was implemented for enhanced user experience.  Since the quest is on harvesting an exact amount of forty-five carrots, if the user harvested less than forty-five carrots, there is a prompt from the farmer to pull more carrots. If the user harvested more than forty-five carrots, the farmer “frowns” and tells Luke, “Over fourty-five. Go back.” At some point in development, I realized that only having the possibility to harvest carrots would impede the user from being able to complete the quest if the user has harvested more than forty-five carrots by accident, so I decided to add the option to replant some carrots – this is one of the changes in my project plan. Last but not least, I find certain little details in the game mechanics are crucial. For example, in Stage 3, the farmer NPC always “faces” Luke, whether Luke is to his right or to his left, mimicking real dialogue.

 

 

Flowchart on Dialogue between Luke and Farmer
Character Traits Table

 

Good technical decisions include setting a game state for which actions happen, structuring characters and objects with behavior (namely Luke, Farmer Giuseppe, message box between Luke and Farmer Giuseppe, shovel, carrot) into classes, structuring code into functions, using arrays to store huge amounts of carrots, designing the game mechanics of the dialogue using if and else if statements, and useful variable names. The game state is crucial because depending on game state, the farmer, carrots and videos may or may not be displayed. Structuring Luke and the Farmer using OOP has been very helpful for organization and readability, and therefore aids in my problem-solving process. Using arrays to store huge amounts of carrots does not only save time, but also helps me control the behavior of certain carrots – whether it’s status is “picked”, “unpicked” or “replanted” based on user behavior. The dialogue is a particularly complex piece of code, thus I paste the snippets below. The first snippet shows the constructor of the message box, which contains x position, y position, image profiles (on the left part of message box to help indicate who is speaking), dialogue_states array, and more arrays containing the speech text of the character(s) for the relevant dialogue_state. The second snippet is a clever way of reducing lines and reusing code as I need to display the profiles as often as I display a dialogue message. The third snippet reveals part of a long function performing actions based on the current dialogue_state. For the “Character Introduction” state, as with many other states, translation has been applied to the message box image and setTimeout is used to have a 200ms cooldown between advances to prevent accidental skips/rapid firing.

class Farmer_Giuseppe_And_Luke_Message_Box {
  constructor(luke_profile, farmer_profile) {
    this.x = 15;
    this.y = 500;

    this.luke_profile = luke_profile;
    this.farmer_profile = farmer_profile;
    this.farmer_quest_progress = "not started";

    this.dialogue_states = [
      "Character Introduction",
      "Quest Introduction",
      "Player Choice Point",
      "Repeated Quest Request",
      "Quest Further Details",
      "Quest Progress",
      "Quest Completed",
      "After Quest",
    ];
    this.dialogue_current_state = this.dialogue_states[0];
    this.intro_messages = [...];
    this.current_message_index = 0;
    this.input_blocked_cooldown = false;
    this.reveal_title_flag = false;

    this.quest_intro_messages = [...];
    this.player_choice_yes = [...];
    this.player_choice_no = [...];
    this.quest_further_details = [...];
    this.quest_progress_messages = [...];
    this.quest_thanks = [...];
  }
display_profiles(person_speaking) {
    if (person_speaking === "???" || person_speaking === "Farmer Giuseppe") {
      push();
      translate(110, 550);
      image(this.farmer_profile, 0, 0, 130, 100);
      pop();
    } else if (person_speaking === "Luke") {
      push();
      translate(110, 550);
      image(this.luke_profile, 0, 0, 100, 130);
      pop();
    }
  }
display_message_box_and_text(farmer_giuseppe_x, farmer_giuseppe_y, luke_x, luke_y, farmer_title, carrots) {
    if (
      dist(farmer_giuseppe_x, farmer_giuseppe_y, luke_x, luke_y) <=
      width / 8
    ) {
      textAlign(LEFT);
      fill(0);

      //--------------------------------------------------//
      if (this.dialogue_current_state === "Character Introduction") {
        push();
        // Center horizontally using message_box width
        translate(width / 2, 550);
        image(message_box, 0, 0);
        pop();

        // Show current message
        let person_speaking =
          this.current_message_index % 2 === 0 ? "Luke" : farmer_title;
        this.display_profiles(person_speaking);
        textSize(17);
        text(person_speaking, 200, 500, 85, 120);
        text(
          this.intro_messages[this.current_message_index],
          300,
          500,
          300,
          120
        );

        // Show continuation prompt
        if (this.current_message_index <= this.intro_messages.length - 1) {
          text("[Click to continue]", 300, 590, 600, 20);
        }

        // Advance dialogue on mouse press
        if (
          mouseIsPressed &&
          !this.input_blocked_cooldown &&
          frameCount % 10 === 0
        ) {
          if (this.current_message_index < this.intro_messages.length - 1) {
            this.current_message_index++;
          } else {
            this.dialogue_current_state = "Quest Introduction";
            this.current_message_index = 0;
          }
          this.input_blocked_cooldown = true;

          // 200ms cooldown between advances
          // Prevents accidental skips/rapid firing
          setTimeout(() => (this.input_blocked_cooldown = false), 200);
        }
      }
...
}

 

4. Problems Encountered & Areas for Improvement

Throughout the course of the project, I encountered many problems which allowed me to improve in my debugging and coding skills. Often, p5js gives feedback on code errors, which point to a line number. I refer to the line number and check the code around it and code associated to objects in that line. I think this has helped me solve many errors, like simple syntax errors involving a missing closing bracket (which can be easy to do when there are nested if conditions within a function within a class), to slightly more complex errors involving something “undefined” (which could be because I forgot to update the path to video/image in preload function). Personally, the very challenging problems are when the game runs without any error p5js throws out, but does not function as intended. These are logical errors. For example, I encountered this problem: the message box is displayed initially when Luke is in the vicinity of the farmer, and after a certain dialogue state is complete, the message box displays when Luke is farther away from the farmer. My intention was to have the message box display only when Luke is near the farmer. I think that this problem was resolved by being even more specific with my if conditions. One of the most challenging unresolved problems for me was that after the second video called in draw() plays, the video in the next chain of states won’t play. I tried to research online, use AI, try different ways (such as using image() in draw but this produced a static frame, using onended() functions, setting an if condition if the time of the video exceeds the duration-1 second of the video) but these all did not work. It was very difficult, and I may have tried to resolve this for about more than five hours, before deciding to give this idea up, and simply having videos that don’t play in consecutive game states.

A key area for improvement include expanding the affordances of the experience through multiple ways such as adding more characters. Another way is to add objects that are not simply part of the background but can interact with the user. By this, I mean objects similar to the tool that can be “grabbed” by the user and used to do something, such as pull carrots. Perhaps, add a painting that can be clicked on and zoomed in, which depicts a painting of the farmer and his family, along with text on their family history in Avella. A third way to expand affordances is to program the code to not only explore new places, but also go back to previously explored places.

MidTerm Report – Final

Blade – Havoc

Blade Havoc is the game I created, inspired by the early 2000s Japanese T.V series called ‘Beyblade’, which I grew up watching. For this project, I wanted to make use of ML5. Particularly hand tracking and voice detection. Due to limited dexterity with my left hand, I realized that an interactive design ins’t something limited to tangible means of input, but should be open to other ends as well. In my case, and of those who find it difficult or boring to play with the conventional design, this project is meant to be a step in a newer direction. A direction and approach made possible thanks to amazing libraries now available online.

About:

Game Link: Click on Me to play  

Github link for the code (commented) : GitHub

Game-Play instructions :  The game makes use of hand gestures and speech recognition. In order to able to play the game, click on the link above which will redirect you to another window.  Zoom in using Command + or Ctrl + to zoom in and increase the size of the canvas for better viewing.  Make sure  to have adequate adequate lighting,  sit about 70- 90 cm away from the laptop in order to be visible to your webcam’s field of vision.  Controls are fairly simple. Pinch your Thumb and Index Finger together to click, and in order to move the on screen pointers, move your hand. You may use either left or right hand of yours, but make sure to use one at a time, as the program is designed to handle one hand at a time. Likewise,  you cannot plug and play two peripheral devices of the same nature at the same time. Not that you cannot do it, but it isn’t practical! The game greats you with animations, sound, and interactive design. The pictures have been photoshopped together to create canvas for the background. Pictures and sounds such as the sound track are borrowed from the show, and I in no circumstance take credit for the ownership or production of these assets. However, I did happen to photoshop – remove background- and put them together in a specific manner alongside color scheming to meet the needs of the game.

How the game works: The game is based on the story of spinning tops which collide with one another and run out of spin. In Japanese culture, this form of play has been quite popular.

Kites and spinning tops from Japan | Turismo Roma

The show takes cultural and historical inspiration from this, and so does my project. You can toggle the instructions button on the ‘Menu’ to understand how the game works. 

Upon clicking, the game first takes you to the game rules window, and by clicking on the arrow at the bottom, it takes you to the game controls window. You can exit by pressing on the ‘close window’ button on the top right of the window pane.

Order of Events: The user first has to toggle the play button in order to proceed with the game.

The game starts with the view of the stadium, and commentator announcing the match between team USA and Japan. The two main characters are Tyson and Daitchi. Each scene proceeds after one of the character is done with their dialogue.

The match then begins with countdown and audio markers.

The beyblades are loaded into the dish, and the window shows the spin status of both the opponent and your beyblade. It shows special attack status to let the user know wether its active or not. In order to activate it , say ” Dragoon Galaxy turbo”. Each of the events, be it impact with other beyblade or activating special move, each has separate audio to it, which makes it even more interactive.

 

Since I happened to move my beyblade out of the stadium, I lost the game. You can try again by heading to the menu. Upon doing so the window will reload and all of the variables and states will be set to default status to avoid any conflict.

Game Controls: Pinch your finger to move your beyblade around. Open them to attack. If thumb and index finger close, you will be able to move, but cannot attack. In that case, you will take hits, untill you either get thrown out of the stadium, or lose out on spin.

 

Joining Thumb And Index Fingers Hand Sign Semi Flat PNG & SVG Design For T-Shirts
Pinch to active virtual click

Proud moment If there is something I am proud of, it is definitely making the sound-classifier and the image-classifier from the ML5 library to get to work. After spending three days trying my best to debug and make the conflict and errors go away, I was finally able to do so. Note that most of the tutorials on ML5.js are in conflict with newer versions of the sdk. Kindly make sure to go over the documentations to avoid any issues. Moreover, I managed to add physics to each blade as well. Upon impact, the opponent’s blade bounces  off of the walls whilst yours upon impact either pushes the other one away or you get hit away. Moreover, if you leave the parameters of the stadium, you end up losing the game. This edge detection and getting it to work is another accomplishment of mine after the implementation of machine-trained classifiers.

The Code:

Reusability and ML5.js : The code is made with modularity and re-usability in mind. For ml5.js , all of the setup code and functions have been moved to common functions to call them inside draw and setup at an instance, without having to go through heaps of code, when choosing to turn off / on the ml5.js features.

function ml5_preload_function(){
    //importing the hand pose image classifier from ml5.js library
  handPose = ml5.handPose({flipped:true}); 
  //importing the sound classifier. Doesn't require additional argument.
 classifier =
   ml5.soundClassifier('https://teachablemachine.withgoogle.com/models/LHGCWnuCY/model.json', ()=>{
//     callback function for testing if the sound model is loaded as it wasn't working before.
   console.log ("sound model loaded");
 });
}


// arranges the setup for ml5
function ml5_setup_logic(){
    handPose.detectStart(video,gotHands);
    classifyAudio();

}



//the logic for ml5 which goes into draw function
function ml5_draw_logic(){
  if(hands.length >0){
    let hand = hands[0];
    let index =  hand.index_finger_tip;
    let thumb = hand.thumb_tip;
    fill(255,0,0);
    let d = dist(index.x,index.y,thumb.x,thumb.y);
    if (d <= 20){
      fill (0,0,255);
      virtual_click = true;
    } else if ( d > 20) {
      virtual_click = false;
    }   
    noStroke();
    circle(index.x,index.y, 16);
    circle (thumb.x,thumb.y, 16); 
    // virtual_click=false
    pointerX_pos = (index.x + thumb.x)/2;
    pointerY_pos = (index.y + thumb.y)/2;
  }
  

These functions are then conveniently called inside the draw and setup functions.

Object Oriented Code : The class ‘Beyblade’ was made use of, which is custom built. Has attributes like spin speed, coordinates, states which return true or false,  and methods like checking for impact.

class Beyblade{
  constructor (pos1 , pos2 ,size , player=true){
    this.xpos = pos1;
    this.ypos = pos2;
    this.size = size;
    this.spin = 100;
    this.special_move = false;
    this.speedX = 2;
    this.speedY = 1;
    this.inside_stadium = true;
    this.stadium_centerX = 316;
    this.stadium_centerY = 200;
    this.centerx = (pos1+size)/2;
    this.centery = (pos2+size)/2;
    this.isPlayer = player;
    this.angle = 0;
  }
  
  
  draw_bey(){
    if (mytitle === "Activated") {
        this.special_move = true ;
        } 
    
    if (this.special_move ===true & this.isPlayer == true) {
      image (player_bey[0],this.xpos,this.ypos,this.size,this.size);
      
      // rotate (this.angle);
      this.angle = this.angle + this.speed;
    } else if (this.special_move ===false & this.isPlayer == true) {
               image (player_bey[1],this.xpos,this.ypos,this.size,this.size);
                 // rotate (this.angle);
                this.angle = this.angle + this.speed;
               } else {
                  image (opponent_bey,this.xpos,this.ypos,this.size,this.size);
                  // rotate (this.angle);
                this.angle = this.angle - this.speed;
               }
  }
  
  move_bey(){
    if (this.isPlayer === true){
      if (virtual_click == true){
        this.xpos = pointerX_pos;
        this.ypos = pointerY_pos;
      }
    } else if (this.isPlayer == false){
      this.xpos = this.xpos + this.speedX;
      this.ypos = this.ypos + this.speedY;
    }
      this.centerx = this.xpos + this.size / 2;
      this.centery = this.ypos + this.size / 2;
  }
  
  check_impact(something) {
    if (dist (this.centerx, this.centery, something.centerx, something.centery) <= this.size) {
      if (virtual_click == false){
        if (this.special_move == true) {
          play_song(9);
          this.xpos += 30;
          this.ypos +=30;
          something.spin = something.spin -10;
          something.speedX = -something.speedX;
          something.speedY = -something.speedY;
        } else {
          play_song(9);
          this.xpos += 30;
          this.ypos +=30;
          something.spin = something.spin - 5;
          something.speedX = -something.speedX;
          something.speedY = -something.speedY;
        }
      } else {
        this.xpos += 30;
        this.ypos +=30;
        this.spin = this.spin - 5;
        play_song(9);
        
        
      }
    }
  }
  
  check_insideStadium(){
    if (dist (this.stadium_centerX, this.stadium_centerY, this.centerx,  this.centery ) > 200){
      this.inside_stadium = false;
    } else {
      this.inside_stadium = true;
    }
  }
  
  bounce_walls(){
  
   let displ = dist(this.stadium_centerX, this.stadium_centerY, this.centerx, this.centery);
  
  if (displ >= 200) { //  214 is the stadium radius
    this.speedX = -this.speedX + random(-1.5, 1.5); 
    this.speedY = -this.speedY + random(-1.5, 1.5);
    
    // Reverse speed direction
    
    console.log("Beyblade bounced!");
  }
    
  }

Training the Model: There were series of steps taken to get both the classifiers to get to work. First, I followed some tutorials online and referred to the Ml5.js documentations to get the hand classifier to work. I set the distance between the two fingers to detect when to consider the click and when not to. Daniel Schiffman’s videos were helpful, but a bit outdated.

Ali being Ali

Got the pointers to work

After setting up the Hand-classifier, I inverted the video and drew in the backside of the canvas. As for the sound classifier, I had to go to Teachable Machine by Google to train a model for detecting specific words for game-control. Due to time constraints, this was more convenient way of training the model, as opposed to me training my own.

I had to train it for background noise and the special phrase that triggers the special move and changes the color and image of the beyblade.

Tuning for desired results.

Finally, the trained model was exported, and was implemented inside the sketch.js and html file to make it able to run.

 

Areas of improvement:

I am proud of the game as of now. It is interactive, helps me to relive my childhood memories, and share this joy with others. However, I wanted to add more levels, ability to change the settings and select different beyblades. This I will add in the future. As far as the game logic goes, I would like to work on the collision physics for the objects. I would like to tumble, roll and push back them forth even more, to make it even more realist.

Overall, I am proud of my work, and how the game turned out to be!

Midterm Progress – ML powered Beyblade game

Introduction:

For this midterm project, I wanted to design something different. Something unique. Something meaningful to me in a way that I get to represent my perspective when it comes  interactivity and design.  Most of the games that I have played growing up, have been AAA gaming titles (top-notch graphics intensive games) on my PSP (Playstation Portable).

Is $75 a good price for a light blue Psp 2000? : r/PSP

Be it Grand Theft Auto or God of War, I have played them all. However, if there is one game that I never got a chance to play on my PSP due to it not being released for that gaming platform , was Beyblade V-Force! It was available on Nintendo Go and other previous generation devices, but wasn’t there for the newer ‘PSP’ that I owned.  I till this date, love that cartoon series. Not only was and am a loyal fan of the show, but I have collected most of the toy models from the show as well.

What's your problems with vforce : r/Beyblade

Brainstorming ideas + User interaction and game design:

This project started off with me wondering what is that one thing dearer to me. After spending an hour just short listing topics that I was interested in , I ended up with nothing. Not because I couldn’t think of any, but because I couldn’t decide upon the one single game. I started this project with a broken hand. My left hand is facing some minor issues, and due to which, I cannot type of hold on to things with the left hand. Particularly my thumb. This made me realize that not only does it make it difficult to program the game, but also to play it as well. My misery made me conscious of users who may struggle with the conventional controls offered typically in the gaming environment : a joystick and some buttons. It made me wonder what can I do different in my case and make this game more accessible to people like me who find it difficult to use a tangible medium to interact with the program. Hence I decided to use hand-tracking technology and sound classification. There is this whole buzz around A.I and I thought why not use a machine learning library to enhance and workout my project. Yet still, I couldn’t finalize a topic or genre to work on.

At first, I came up with the idea of a boxing game. Using head-tracking and hand tracking, the user will enter a face-off with the computer, where he/she will have to dodge by moving head left or right to move in the corresponding direction. To hit, they will have to close hand and move their whole arm to land a punch.

Basic Layout visualized.

Flow chart of basic logic construct

I drafted the basic visuals and what I wanted it to look like, but then as I started to work, I realized that violence is being portrayed and is not but un-befitting for an academic setting. Moreover, I wasn’t in a mood to throw punch and knock my laptop down, since I am a bit clumsy person. This was when my genius came into being. 1 day before, I decided to scrap the whole work and get started again on a new project. This time, it is what I love the most. You guessed it right – it is beyblade!

Basic gameplay features:

The whole idea revolves around two spinning metal tops with a top view,  rotating in a stadium. These tops hit one another, and create impact. This impact either slows them down, or knocks one out , and even sometimes both out of the stadium. The first one to get knocked out or stops spinning loses, and the other one wins.  I wanted to implement this, and give user the ability to control their blades using hand gesture. The user will be able to move their blade around using their index finger and thumb pointing and moving in the direction they would like their blade to move. The catch however, is that only when the thumb and index finger are closed, only then you will be able to move the blade, and to attack, only when your thumb and index finger are not touching, only then will you be able to attack and inflict damage on opponent. To save yourself from damage, you either dodge, or keeping fingers opened. These control constructs are unique and are not implemented in any game design of similar genre or nature before. I came up with this, because I cannot properly grab using my left thumb and index finger, and hence wanted to use them in the game.

Game states

I have decided to use states to transition between the menu, instruction screen, gameplay , showing win/lose screen, and returning back to the menu. This makes it convenient to use the modular code and use it inside the ‘draw’ function.

Legal Stadiums-[bc]These are the legal tournament stadiums that bladers can agree to battle on in Official Ranked Battles.[
Stadium  used in the game.
      • ML5:

        To make the controls workout, I will have to rely on Ml5.js. ML5 allows machine learning for web-based  projects. In  my case, I will be making use of handPose and soundClassifier modules, which happen to be pre-trained models. Hence, I won’t have to go through the hassle of training a model for the game.

 

handPose keypoints diagram

Using the key points 4 and 8, and by mapping out their relative distance, I plan on tracking and using these to return boolean values, which will be used to control the movement of the blade. I referred to coding-train’s youtube Chanel as well to learn about it, and implement it into my code.

I am yet to figure out how to use sound-classification, but will post in my final project presentation post.

 Code (functions, classes, interactivity):

Class and Objects – Pseudo code.

Though I am yet to code, and due to limited mobility , my progress has been slowed. Nonetheless, I sketched out the basic  class and constructor function for both objects (i.e player and the opponent). Each blade will have speed, position in vertical and horizontal directions, as well as methods such as displaying and moving the blade. To check for damage and control the main layout of the game, if and else statements will be used in a separate function, will then be called inside the ‘draw function’.

Complex and trickiest part:

The trickiest part is the machine learning integration. During my tests, hand gesture works, but despite training the sound classifier, it still doesn’t return true, which will be used to trigger the signature move. Moreover, I want there to be a delay between user’s hand -gesture and the beyblade’s movement in that particular direction. This  implementation of ‘rag doll’ physics is what is to  be challenging.

Tackling the problems and risks:

To minimize the mess in the p5 coding environment, I am defining and grouping related algorithmic pattern into individual functions, as opposed to dumping them straightaway into the ‘draw’ function. This helps me in keeping the code organized and clean, and allows me to re-use it multiple times. Secondly, using Ml5.js was a bit risky, since this hasn’t been covered in the class, and the tutorial series does require time and dedication to it. Cherry on top, limited hand mobility put me at disadvantage. Yet still, I decided to go with this idea, since I want it to simply be unique. Something which makes the player play the game again. To make this possible, I am integrating the original sound-track from the game, and am using special effects such as upon inflicting damage.  Asides from the theming, I did face an issue with letting the user know wether their hand is being tracked or not in the first place. To implement it, I simply layers the canvas on top of the video, which solved the issue for me. As of now, I am still working on it from scratch , and will document further issues and fixes in the final documentation for this mid-term project.

 

Midterm Project – Balloon Popper

Ever been at a wedding or party, locked in deep conversation, when suddenly—a balloon drifts by, practically begging to be popped? You hesitate. Would it be childish? Would people stare? Well, worry no more! Balloon Popper is here to satisfy that irresistible urge. No awkward glances, no judgment—just pure, unfiltered balloon-bursting joy.

Project Overview

Balloon Popper is a simple game that I worked on, though not always with ease. The objective is to pop balloons as they fall from the top of the canvas using a shooter that fires “bullets” from the bottom. The game consists of a start page, a game environment, and a finish page. It utilizes classes to define key elements such as the shooter, bullets, and balloons, each with specific properties that support collision detection, interaction, and display functions.

Implementation

The game begins with a start page where the player can view the instructions by clicking the instructions button or start the game by pressing the start button. Once the game starts, the player must shoot the balloons before they reach the bottom of the canvas. The player moves left and right along four paths using the arrow keys and fires bullets using the spacebar.

At the top of the canvas, three score trackers display the number of lives, balloons popped, and stray bullets. The lives counter tracks how many balloons have passed the bottom of the canvas, while the stray bullets counter keeps track of bullets that were fired but missed the balloons. If either the lives or stray bullets count reaches five, the game ends. The number of balloons popped is also displayed, but there is no specific win condition—the player can continue playing and challenge themselves to improve their score.

When the game ends, the finish page appears, displaying the reason for the loss, whether due to missing five balloons or using up all stray bullet allowances. The end screen also includes a restart button, allowing the player to reset the game and play again.

Code Highlights

function displayTextBox(textStr, x, y, textColor) {
  textSize(16);
  textStyle(BOLD);
  textFont("Poppins");
  let textWidthValue = textWidth(textStr);
  let padding = 5;

  fill(255, 255, 255, 200);
  rect(x - padding, y - 15, textWidthValue + 10, 20, 5);

  fill(textColor);
  textAlign(LEFT);
  text(textStr, x, y);
}

I particularly love the code snippet above that defines how I displayed the score trackers at the top of the canvas.

  isHit(bullet) {
    return dist(this.x, this.y, bullet.x, bullet.y) < this.r / 2;
  }
}

for (let i = balloons.length - 1; i >= 0; i--) {
  balloons[i].update();
  balloons[i].display();

  for (let j = bullets.length - 1; j >= 0; j--) {
    if (balloons[i].isHit(bullets[j])) {
      playPopSound();
      balloonsPopped++;
      balloons[i].reset();
      bullets.splice(j, 1);
      break;
    }
  }

The above two code snippets show how to detect collision between the bullet and the balloon.

Challenges and Areas for Improvement

One of the main challenges I faced was styling the game, including selecting colors, font sizes, and text styles. I realized that I need to work on improving my design skills. Loading the balloon images was another issue, but after consulting resources such as Stack Overflow and AI tools, I was able to find a solution and successfully display the images.

This project has been a great learning experience, and I plan to build on what I’ve learned. In the future, I want to improve button management, refine the game’s sound integration, and enhance the overall visual design to make the game even more engaging. Additionally, I would like to optimize the collision detection and fine-tune the difficulty scaling to provide a more dynamic challenge for players.

ENJOY;

Midterm Project

🎉Project Description

“Aura Farming” is an interactive game inspired by Dragon Ball Z, where players take control of Goku and help him transform into a Super Saiyan by rapidly pressing the spacebar. The game challenges players to increase Goku’s power level within a 30-second time limit, visually represented by the growth of his aura and transformation into his iconic Super Saiyan form. The game combines dynamic animations, sound effects, and scoring mechanics to create an engaging experience.

The gameplay revolves around pressing the spacebar to “power up” Goku, increasing his power level and triggering visual changes such as aura expansion and sprite animations. Once Goku’s power level exceeds 9000, he transforms into a Super Saiyan, with golden aura effects and looping animations representing his heightened state. 

 

 

📋Assignment Brief

The assignment required creating an interactive artwork or game using p5.js while incorporating certain elements:

The game responds to user input via:

  • Pressing the spacebar to increase Goku’s power level.
  • Clicking the mouse to navigate between game states (e.g., start screen, instructions screen, and score page).
  • The score page allows restarting the game by clicking anywhere on the screen.

The aura visuals are created using shapes:

  • A combination of ellipses and vertex-based polygons.
  • The aura dynamically grows in size as Goku’s power level increases.

Multiple images (sprites) are used throughout the game:

  • Goku’s base form transformation is represented by 8 sprites, which cycle during animation.
  • Super Saiyan mode is represented by 6 sprites, which loop continuously while in that state.
  • Background images are used for different screens (start screen, instructions screen, gameplay, and score page).

The project includes both sound effects and background music:

  • Background music plays during different game states:
    • Start screen: Non-battle music.
    • Gameplay: Battle music.
    • Score page: Victory music.
  • Sound effects play when powering up (e.g., pressing the spacebar).

On-screen text is used for:

  • Instructions on the start screen and instructions screen.
  • Displaying Goku’s current power level during gameplay.
  • Showing the final score and high score on the score page.
  • Feedback such as “Time Left” during gameplay.

The game utilizes OOP principles through the Character class:

  • Encapsulates properties such as powerLevel, auraSize, and isSuperSaiyan.
  • Includes functions such as powerUp(), drawEnergyAura(), and transformToSuperSaiyan().
  • Handles animations by cycling through arrays of sprites based on game state.

After the experience is completed, there is a way to start a new session (without restarting the sketch)

  • The experience starts with a start screen that waits for user input (mouse click) to proceed to the instructions or gameplay screen.
  • After gameplay ends (30-second timer), a score page is displayed, showing the player’s final score and high score.
  • Players can restart the game from the score page without needing to reload or restart the sketch.

💻Process

Initial Setup and Planning

Initially, the project began with the idea of creating a simple interactive game inspired by Dragon Ball Z. The goal was to replicate Goku’s iconic transformation into Super Saiyan while providing players with an engaging challenge through rapid key presses.

  • Defining Core Mechanics: The primary mechanic involved pressing the spacebar to increase Goku’s power level, which would trigger visual changes (aura growth and sprite animations) and sound effects.
  • Outlining Game States: The game required distinct states: a start screen, instructions screen, gameplay screen, and score page. Each state would serve a specific purpose in the user experience.
  • Sketching Designs: Basic designs for Goku’s aura effects were sketched out to guide development.

Loading Assets

The next step was to load all necessary assets- images, sounds, and fonts- into the project using the preload() function. This was crucial to ensure smooth gameplay without runtime delays. 

  • Arrays of images were created for Goku’s base form transformation (8 frames) and Super Saiyan mode (6 frames). With a for loop, I was able to dynamically load these images into arrays powerUpFrames and superSaiyanFrames, reducing repetitive code.
for (let i = 1; i <= 8; i++) {
  powerUpFrames.push(loadImage(`/images/Base Goku- Sprite ${i}.png`));
}
for (let j = 1; j <= 6; j++) {
  superSaiyanFrames.push(loadImage(`/images/Super Saiyan Goku- Sprite ${j}.png`));
}
  • Four different backgrounds were loaded for the start screen, instructions screen, gameplay screen, and score page.
  • Background music tracks were loaded for each game state (non-battle music, battle music, victory music), along with sound effects for powering up.

Creating the Character Class

To encapsulate Goku’s properties and behaviors, I created the Character class. This class served as the foundation for managing animations, aura effects, and transformations. Key features of the class included:

  • powerLevel: Tracks Goku’s current power level.
  • aurasSize: Controls the size of Goku’s aura.
  • isSuperSaiyan: Boolean flag indicating whether Goku is in Super Saiyan mode.
  • Arrays for animation frames (powerUpFrames and superSaiyanFrames) were used to manage sprite animations.
  • powerUp(): Increases Goku’s power level and aura size when the spacebar is pressed.
  • transformToSuperSaiyan(): Triggers Goku’s transformation into Super Saiyan once his power level exceeds 9000.
  • drawEnergyAura(): Dynamically draws Goku’s aura using shapes (ellipses and vertex-based polygons) with Perlin noise for organic movement.
  • reset(): Resets all properties to their initial values when restarting the game.
class Character {
  constructor(name, x, y) {
    // Name of the character (e.g., "Goku").
    this.name = name;
    // X and Y coordinates for positioning the character on the canvas.
    this.x = x;
    this.y = y;
    // Tracks the current power level of the character.
    this.powerLevel = 0;
    // Multiplier used to increase power level faster during Super Saiyan mode.
    this.powerLevelMultiplier = 1.0;
    // Controls the size of the aura surrounding the character.
    this.auraSize = 0;
    // Stores the current sprite image for the character (e.g., normal or Super Saiyan).
    this.sprite = null;
    // Scale factor used to resize sprites when drawing them on the canvas.
    this.scaleFactor = 0.5;
    // Number of points used to create the aura shape (polygon).
    this.auraPoints = 12;
    // Offset value for Perlin noise, used to create organic movement in the aura.
    this.auraNoiseOffset = random(1000);
    // Offset value for aura color animation (e.g., cycling between yellow and red).
    this.auraColorOffset = 50;
    // Boolean flag indicating whether the character is in Super Saiyan mode.
    this.isSuperSaiyan = false;
    // Delay between animation frames (controls animation speed).
    this.animFrameDelay = 1000;
  }

  // The display() method handles rendering the character and its associated visuals (sprite, aura, power level text).
  display() {
    // Draws Goku's energy aura using the drawEnergyAura() method.
    this.drawEnergyAura();

    // Determines which sprite to display based on Goku's state (normal, powering up, or Super Saiyan).
    let currentSprite;

    if (this.isSuperSaiyan) {
      // If Goku is in Super Saiyan mode, cycle through Super Saiyan animation frames.
      let index = floor(frameCount / 5) % superSaiyanFrames.length;
      currentSprite = superSaiyanFrames[index];
    } else if (this.powerLevel > 0) {
      // If Goku is powering up, cycle through base form transformation animation frames.
      let index = floor(frameCount / 5) % powerUpFrames.length;
      currentSprite = powerUpFrames[index];
    } else {
      // If no transformation is active, display Goku's normal sprite.
      currentSprite = normalSprite;
    }

    // Draws the selected sprite at Goku's position with scaling applied.
    let scaledWidth = currentSprite.width * this.scaleFactor;
    let scaledHeight = currentSprite.height * this.scaleFactor;
    image(currentSprite, this.x, this.y, scaledWidth, scaledHeight);

    // Displays Goku's current power level at the top of the screen.
    fill(255);
    stroke(117, 117, 116);
    fill(149, 152, 173);
    rect(200, 70, 400, 150, 30);
    noFill();
    fill(255, 166, 0);
    rect(220, 80, 360, 130, 20);
    noFill();
    fill(255);
    textFont("Helvetica", 50);
    textAlign(CENTER);
    text("Power Level", 400, 120);
    text(`${this.powerLevel}`, 400, 180);
    noFill();
  }

  // The drawEnergyAura() method creates dynamic visuals for Goku's aura based on his power level and state.
  drawEnergyAura() {
    push(); // Saves the current drawing state.

    translate(this.x, this.y); // Moves the origin to Goku's position.

    if (this.isSuperSaiyan) {
      // If Goku is in Super Saiyan mode, use a golden color for his aura.
      fill(255, 215, 0, 150);
      stroke(255, 215, 0, 200);
    } else {
      // If Goku is in base form or powering up, use a yellow color for his aura.
      fill(255, 255, 0, 100);
      stroke(255, 255, 0, 150);
    }

    strokeWeight(2); // Sets the thickness of the aura outline.

    beginShape(); // Starts defining a custom shape for the aura.

    const baseRadius = this.auraSize * 0.8; // Base size of the aura shape.
    const spikeMagnitude = this.auraSize * 0.2; // Magnitude of spikes in the aura for a dynamic effect.

    // Loop through points to define the aura shape.
    for (let i = 0; i < this.auraPoints; i++) {
      const angle = map(i, 0, this.auraPoints, 0, TWO_PI); // Calculate angle for each point.
      const noiseVal = noise(
        this.auraNoiseOffset + i * 0.1 + frameCount * 0.05
      ); // Use Perlin noise for organic movement.
      const dynamicRadius = baseRadius + spikeMagnitude * noiseVal; // Adjust radius based on noise value.
      const variedAngle = angle + radians(map(noiseVal, 0, 1, -10, 10)); // Add randomness to angles.

      // Define each vertex of the aura shape.
      vertex(
        dynamicRadius * cos(variedAngle),
        dynamicRadius * sin(variedAngle)
      );
    }

    endShape(CLOSE); // Close the custom shape.

    // Update animation parameters for smooth movement.
    this.auraNoiseOffset += 0.02; // Increment noise offset to animate aura.
    this.auraColorOffset += 0.1; // Increment color offset for potential color cycling.

    pop(); // Restores the previous drawing state.
  }

  // The powerUp() method increases Goku's power level and aura size when called (e.g., pressing the spacebar).
  powerUp() {
    this.powerLevel += 100 * this.powerLevelMultiplier; // Increase power level based on multiplier.
    this.auraSize += 3; // Gradually increase the size of Goku's aura.
  }

  // The reset() method reverts Goku's properties to their initial values (used when restarting the game).
  reset() {
    this.powerLevel = 0; // Reset power level to zero.
    this.auraSize = 10; // Reset aura size to its default value.
    this.isSuperSaiyan = false; // Reset Super Saiyan mode to false.
    this.powerLevelMultiplier = 1.0; // Reset power level multiplier to its default value.
    this.sprite = normalSprite; // Set Goku's sprite back to his base form.
  }

  // The transformToSuperSaiyan() method triggers Goku's transformation into Super Saiyan mode.
  transformToSuperSaiyan() {
    this.isSuperSaiyan = true; // Set Super Saiyan mode to true.
    this.powerLevelMultiplier = 50; // Dramatically increase the power level multiplier (e.g., x50 boost).
    this.auraSize += 50; // Increase aura size significantly to reflect transformation.

    // Change Goku's sprite to his Super Saiyan form.
    this.sprite = superSaiyanSprite;
  }
}

Implementing Game States

The game required distinct states to guide players through the experience:

  • Start Screen: Displayed the game title (“Aura Farming”) along with buttons for starting the game or viewing instructions. Mouse clicks were used to navigate between screens.
  • Instructions Screen: Provided players with guidance on how to play the game (e.g., “Press SPACEBAR rapidly to power up”).
  • Gameplay Screen: Served as the main interactive phase where players pressed the spacebar to increase Goku’s power level within a 30-second timer.
  • Score Page: Displayed the player’s final score, high score, and an option to restart the game.

State management logic was implemented in the draw() function using boolean flags (startScreen, instructionScreen, gameScreen, scorePage) to control which screen was displayed.

Adding Animations

An array of 8 sprites (powerUpFrames) was used to represent Goku powering up and an array of 6 sprites (superSaiyanFrames) represented Goku in his Super Saiyan form. 

The display() method cycled through these frames using frameCount:

let index = floor(frameCount / animFrameDelay) % powerUpFrames.length;
currentSprite = powerUpFrames[index];

Integrating Sound Effects and Music

To enhance immersion, sound effects and background music were added using p5.js sound functions:

  • Background music tracks were assigned to each game state (e.g., non-battle music on start screen, battle music during gameplay).
  • A powering-up sound effect played whenever the spacebar was pressed. Conditional checks (isPlaying()) ensured sounds did not overlap or restart unnecessarily.

Implementing Scoring System

A scoring system was added to track the player’s performance

    • The player’s current power level was displayed during gameplay
    • After gameplay ended (30-second timer), a score page displayed:
      • Final score based on Goku’s highest power level achieved.
      • High score saved across multiple play sessions using an array (previousScores).
let previousScores = [];

 

Restart Functionality

The final milestone involved adding functionality to restart the game without reloading or restarting the sketch:

  • Clicking anywhere on the score page reset all properties (e.g., power level, aura size) using the reset() method in the Character class.
  • State flags were updated to return players to the start screen.

🚩Challenges Faced

Assest Loading Issues: One of the initial challenges was loading images correctly due to incorrect file paths or naming conventions. This caused errors where sprites failed to appear in the game.
Solution: Carefully checked file paths, ensured consistency in naming conventions.

Animation Logic: Initially struggled with sprite animations cycling incorrectly or not looping smoothly during transformations.
Solution: Adjusted animation logic in the display() method of the Character class to cycle frames based on frameCount, ensuring smooth transitions.

Sound Overlapping: Sounds repeatedly played or overlapped when keys were pressed rapidly during gameplay.
Solution: Used conditional checks (isPlaying()) before playing sounds to prevent overlapping audio playback.

Game Restart Logic: Ensuring that all game states reset properly when restarting from the score page was challenging.
Solution: Added a reset() method in the Character class to revert all properties (e.g., power level, aura size) to their initial values.

 

function mouseClicked() {
  if (
    startScreen == true &&
    mouseX > 270 &&
    mouseX < 530 &&
    mouseY > 310 &&
    mouseY < 390
  ) {
    gameScreen = true;
    startScreen = false;
    gameStartTime = millis(); // Record the starting time of the game
  }

  if (
    startScreen == true &&
    mouseX > 170 &&
    mouseX < 630 &&
    mouseY > 510 &&
    mouseY < 590
  ) {
    instructionScreen = true;
    startScreen = false;
  }

  if (
    instructionScreen == true &&
    mouseX > 340 &&
    mouseX < 460 &&
    mouseY > 610 &&
    mouseY < 650
  ) {
    instructionScreen = false;
    startScreen = true;
  }

  if (scorePage == true) {
    // Restart the game:
    victoryMusic.stop();
    scorePage = false;
    startScreen = true; // Return to the start menu
    player.reset(); // Reset player's power level and aura size
  }
}

 

📶Key Take Aways and Future direction

This project has taught and solidified a lot of skills that the class established.

    • Improved proficiency in handling animations using arrays of images and frame-based logic.
    • Enhanced problem-solving skills through debugging asset loading issues and refining animation transitions.
    • Learned how to manage sound effects effectively in interactive applications.
    • Developed a better understanding of OOP principles by structuring code with classes and methods.

I particularly enjoyed designing Goku’s transformation sequence into Super Saiyan- his was technically challenging yet felt extremely fulfilling for when I did manage.

If I were to revisit this project, I would consider adding more dynamic gameplay elements, such as obstacles or enemies that interact with Goku’s aura. Another thing I would do is introduce multiple playable characters, such as Vegeta, Piccolo, or other iconic figures from Dragon Ball Z. Players could select their character on the start screen, with each character having unique abilities and animations. For example, Vegeta might power up faster but have a smaller aura, while Piccolo could regenerate power when idle. To implement this, I would extend the Character class to include properties like characterName, spriteSet, and specialAbility. This feature would add replayability and variety to the game, encouraging players to explore different characters and strategies.

To visually reflect Goku’s increasing power level, I would implement dynamic backgrounds that change as the player progresses. At low levels, the background could feature a calm landscape like Planet Namek. At mid-levels, the sky could darken with storm clouds forming, while at high levels, lightning strikes and debris flying around could create a chaotic environment. This feature could be implemented by layering multiple background images and transitioning between them using alpha blending or animations triggered by power level thresholds. Dynamic backgrounds would add excitement to gameplay and visually emphasise the intensity of Goku’s transformation.

✅Delivered Project

The final version of Aura Farming successfully delivers:

    • A complete interactive experience where players help Goku transform into Super Saiyan by rapidly pressing the spacebar.
    • Smooth animations for both base form transformation (8 frames) and Super Saiyan mode (6 frames).
    • Dynamic aura visuals that grow organically as Goku powers up.
    • Background music tailored to different game states (start screen, gameplay, score page) along with sound effects for powering up.
    • A scoring system that tracks high scores across multiple play sessions.
    • Fully functioning start screen, instructions screen, gameplay timer (30 seconds), and score page with restart functionality.

Midterm :)

Project Concept

This project is a simple point and click game based on SpongeBob’s world. The player starts outside SpongeBob, Patrick, and Squidward’s houses and can click on them to enter different rooms. Each room has its own design and sometimes interactive elements like sounds, books, or TV screens. The goal is to explore different parts of their world and experience small interactions.

link to the sketch: https://editor.p5js.org/flipflops/full/Z69RYq4v1

To make the game feel more personal, I drew all the rooms and the background instead of using images online. I tried making it so that all the drawings blend well with the objects I coded, so everything feels like part of the same world:

How it works

The game constantly checks where the user is and updates the background based on their location. When the player clicks on a house, the game detects which house was clicked and then changes the background to the correct room image. Some rooms also have extra interactive features, like playing specific sounds or changing visuals when clicked.

For example, the TV room cycles through different screens each time the player clicks, making it feel like the TV is actually changing channels. The book room has different pages that the player can flip through, and each page includes a funny SpongeBob quote. The game also manages background music, so when the player moves between different rooms, it plays the correct theme without overlapping sounds. Another thing I focused on was making sure the back button always works properly, so the player can return outside without any weird glitches.

Code highlight

One of the coolest parts that I’m proud about is the clarinet room, where the player can actually play Squidward’s clarinet. There are seven different notes, and clicking on different parts of the clarinet will play them. It’s like a mini music feature inside the game, and it makes Squidward’s room more interesting instead of just being another background.

function checkClarinetHoleClick(mx, my) {
  // all the clarinet holes coordinates (left to right) stored in array
  let clarinetHoles = [
    { x: 174, y: 153 },
    { x: 190, y: 153 },
    { x: 205, y: 153 },
    { x: 218, y: 153 },
    { x: 245, y: 152 },
    { x: 260, y: 152 },
    { x: 274, y: 152 },
  ];

  for (let i = 0; i < clarinetHoles.length; i++) {
    //distance between mouse click and centre of each hole
    let d = dist(mx, my, clarinetHoles[i].x, clarinetHoles[i].y);
    if (d < 5) { // within 5 pixels
      // hole clicked
      playClarinetSound(i); // play note
      break;
    }
  }
}

 

Improvement

One issue I ran into was getting the highlight effect to work when hovering over objects. I wanted players to see which items they could interact with, but at first, the effect wasn’t showing up correctly. After some testing, I made sure the game checks the mouse position and only highlights objects when the cursor is over them.

In the future, I would like to add more interactive elements, like clickable objects inside rooms that trigger animations or extra dialogues. Right now, the game works fine, but adding more details would make it feel more complete. Also, the game doesn’t have a clear goal, so maybe adding a small mission or hidden secrets to find would make it more fun.

Midterm Project – Cat Rescue Game

 

Midterm Project – Cat Rescue Game

For my midterm project, I was very excited to create a game based on something that I love, cats! As I have grown up and lived in Abu Dhabi for half my life, I have noticed that there are a lot of stray cats. So with this in mind, I wanted to design a game where the player walks around a city, rescues stray cats, and takes them to a shelter. I was inspired by a photography project I completed last semester about the spirit of street cats in Abu Dhabi. I went around the city in Abu Dhabi and captured these cats’ lives and the environment they are in. (link to the photos). The game combines movement mechanics, object interactions, and a simple pet care system. The goal of the game is to rescue and rehome all the stray cats in order to win the game. I started this midterm project by drawing a rough sketch of how I wanted it to look like, and the various screens I wanted to implement. 

Link to sketch:

Midterm Sketch

 

Final Game:

Link to final game

Essentially, my game consists of three main screens, the start, game, and restart screen. I wanted a specific look for my background that I was not able to find online, so I decided to create my own. For both the start screen and the game background screen, I used Illustrator to make various shapes and used some images like trees or garbage bins. Then I converted these to PNG files so that I was able to upload them into p5.js and use them in my code. For the shelter, I used different shapes to make it look like a house. Additionally, I made the start screen display a box with on-screen text explaining how to play the game. Similarly, the restart screen also has a circle with on-screen text showing that you won, and a button to restart. For the interaction aspect of my project, I implemented a way for the player to control the girl using the arrow keys on the keyboard to move around. The stray cats are located at random locations in the city and if the girl touches a cat, it is rescued and sent to a shelter. I also used happy, chill background music that I found fitting to the game that starts once you press “Start Game”.

Overall I am extremely satisfied with the way that my final game turned out. Something I am particularly proud of is that instead of using pre-made designs from the internet, I designed my own backgrounds in Illustrator, which gives my game the unique quality I was seeking. Also, I am proud that I was able to successfully implement a collision detection system that ensures that once the player rescues a cat, it gets added to the shelter. I also liked the three-screen system (Start → Game → Restart) which provides the game with a clear structure. Lastly, I am extremely proud that I was able to draw inspiration from my real-life experiences in Abu Dhabi, which makes the game more unique and personal to me. I was able to connect my previous photography project and this game, linking different creative disciplines. I like that my game has an underlying story about spreading awareness about stray cats, which adds an emotional layer to my project.

 

Car class (which represents the girl’s movement):

class Car {
  constructor() {
    this.x = width / 2;
    this.y = height - 80;
    this.size = 50;
  }

  move() {
    if (keyIsDown(LEFT_ARROW)) this.x -= 5;
    if (keyIsDown(RIGHT_ARROW)) this.x += 5;
    if (keyIsDown(UP_ARROW)) this.y -= 5;
    if (keyIsDown(DOWN_ARROW)) this.y += 5;

    // Keep girl inside canvas
    this.x = constrain(this.x, 0, width - this.size);
    this.y = constrain(this.y, 0, height - this.size);
  }

  display() {
    image(carImage, this.x, this.y, 60, 100);
  }

 

Throughout developing this game, I faced a few challenges that required me to problem-solve. One of the issues was ensuring that the text box and circle were layered properly over the background so they remained visible. It took me some time to adjust their positioning and layering so that they were correctly visible on the screen. Another challenge I came across was making sure that the girl’s movement worked smoothly in all directions (up, down, left, and right). Debugging this movement system took some trial and error, but I was able to fix it. Additionally, I ran into smaller, frustrating issues, like file name errors, for example, a missing capital letter caused images not to load properly. Debugging these minor but important details taught me the importance of careful file management. However, I was able to overcome these challenges and successfully build a functioning game. 

If I had more time, there are a few features I would have liked to add to enhance the user experience. One idea was to expand on the rescue aspect, right now, when the cats reach the shelter, they are considered rescued. However, I would have liked to add an extra step where the player needs to care for the cats (feeding them, treating injuries, etc.) before they are fully rescued. Another improvement would be to introduce different difficulty levels (Easy, Medium, Hard) by adding obstacles that the player must overcome to rescue the cats. Also, smaller interactive details, like the cats meowing when clicked, would also add to the game. Even without these extra features, I am really happy with how my game turned out. This project challenged me to problem-solve, debug, and think creatively, and I’m proud of what I was able to accomplish.

 

Music citation:

Music track: Marshmallow by Lukrembo

Source: https://freetouse.com/music

Midterm Project

Concept

Link to Sketch: https://editor.p5js.org/sa8831/sketches/R-3aQof8X

Inspired by a small app I made during high school (Refer to the blog about Midterm progress),  I decided that for the upcoming midterm project, to create an interactive visual novel game. The game takes place in a school of “The Periodic Table” where chemical elements are personified as classmates and teachers. Throughout the game, the user plays as a personified version of Carbon meets other elements like Hydrogen and oxygen to discuss who they are. However, there are 2 endings to this game, where after interacting with either characters, each gets a different ending and a different activity.

How the game works:

How the Periodic Table Academy Game Works (Updated Version):

  • Starting the Game:
    • When the game starts, a title screen with a Play button appears. Upon clicking the Play button, the game transitions to the instruction screen.
    • Instructions are displayed, welcoming the player to the Periodic Table Academy and explaining that the player can click the Play button again to begin the game. The player is presented with two characters to interact with: Oxygen and Hydrogen. The characters are displayed on the screen, and the player can choose who to talk to by selecting an option like “Talk to Oxygen” or “Talk to Hydrogen”.
    • If the player chooses to talk to Oxygen, they enter the oxygen-talk state. Oxygen responds with different dialogue options like:
      • How are you?
      • Tell me about yourself
      • Bye
    • Based on the selected option, the game displays different responses from Oxygen, with the dialogue box updating each time.
    • If the player selects “Bye”, the game moves into a cutscene where Oxygen says goodbye, and then the game transitions to one of the endings after a short delay (CO2).Hydrogen’s Dialogue:
      • Similarly, if the player chooses to talk to Hydrogen, they enter the hydrogen-talk state. Hydrogen responds with dialogue options such as:
        • How are you?
        • Tell me about yourself
        • Bye
      • The game progresses similarly as with Oxygen, with the player receiving different responses from Hydrogen.
      • Selecting “Bye” leads to a cutscene where Hydrogen says goodbye, followed by a transition to another ending (C-H).

 

Endings:

        • There are two possible endings:
          • CO2 (Carbon Dioxide): If the player interacts with Oxygen, they receive the CO2 ending. The game then displays a message congratulating the player for making CO2.
          • C-H (Hydrocarbon): If the player interacts with Hydrogen, they receive the Hydrocarbon ending. The game congratulates the player for making Hydrocarbons.Interactive Ending:
            • During the ending state, the player can click around the screen to generate particles that represent either CO2 or Hydrocarbons depending on the ending.
            • Particles are displayed on the screen, and each particle shows a label (either “CO2” or “C-H”) as it moves upward. These particles are generated when the player clicks anywhere on the screen.

Game Design

I initially wanted to draw a personified Carbon and allow the user to move using keys A and D to include a walking animation, to go either direction to the characters. However, due to breaking the screen and difficulty to link my spritesheet with the character, I removed that idea but instead made it inspired by the game Undertale:

Undertale Part #12 - Dating Start!

(inspiration for the dialogue)

In addition to this, the endings involves particles that resembles a “bond” between 2 characters. I aim for the particles to represent the compounds for reacting Carbon with either Oxygen or Hydrogen to create molecules (like C-H or Hydrocarbons, and Carbon Dioxide or CO2).

 

Highlights/ Challenges:
The highlights of this would be this snippet:

// Particle Class
class Particle {
  constructor(x, y, text) {
    this.x = x;
    this.y = y;
    this.size = random(20, 50);
    this.text = text;
    this.ySpeed = random(-2, -1);
  }

  move() {
    this.y += this.ySpeed; // Move upward
  }

  display() {
    fill('#ADD8E6');
    noStroke();
    ellipse(this.x, this.y, this.size);
    fill(255);
    textSize(this.size / 2);
    text(this.text, this.x, this.y);
  }
}

// Generate particles on click
function mousePressed() {
  if (state === 'ending') {
    let newParticle = new Particle(mouseX, mouseY, endingType);
    particles.push(newParticle);
  }
}

Because of clicking around the ending screen to get the needed “molecule” for each ending.

However, the challenges involves the following:

  1. Ensuring smooth user interaction with the character dialogues was challenging, especially with different choices for interactions such as “How are you?”, “Tell me about yourself?”, and “Bye.”
    • I structured the dialogue system using buttons that allow for straightforward user input. This kept the interactions clean, with each character giving distinct options based on the user’s previous choices. This helped in providing a more guided yet flexible experience.
  2. Since I wanted to integrate Object-Oriented Programming, handling multiple characters (Oxygen and Hydrogen) with unique behaviors, interactions, and background transitions was tricky, especially with the game requiring seamless transitions from one scene to another.
    • I utilized OOP principles to create classes for characters, backgrounds, and game states. This allowed for easy management of multiple elements interacting with each other, while ensuring that transitions and character interactions felt fluid and natural. The background changed dynamically as Carbon moved, which helped convey the progression of the game.
  3. Another challenge was implementing multiple endings depending on which character the player interacts with first and ensuring the game could be easily restarted without refreshing the page.
    • I included an instruction screen and a restart button after each ending. To handle game state management, I kept track of the character interactions and ensured the game’s ending sequences could be triggered based on the order of choices. The restart button was designed to reset the game state while keeping the experience accessible without needing to reload the page.
  4. The game’s concept of displaying chemistry information such as oxygen bonding with carbon, and visual representations of molecules like CO2 and hydrocarbons, needed to be both educational and engaging.
    • I decided to keep the visual representations simple, using floating shapes and rain animations to visually communicate the chemical reactions. This allowed players to understand the results of their choices (CO2 and hydrocarbons) in a non-overwhelming way.

Improvements

  • Enhancing Character Interactions:

    • Add more diverse dialogue options that react to previous choices, making conversations more personalized and dynamic.
  • Expanding the Periodic Table Academy Environment:

    • Introduce additional elements from the periodic table with unique interactions, personalities, and visual effects.
    • Create puzzles or mini-games based on chemical properties to increase educational value.
  • Improved Visual Effects for Chemical Reactions:

    • Implement particle effects, such as glowing or color-changing molecules when bonding occurs, to enhance visual appeal and illustrate chemical reactions more vividly.