Reading Reflection – Week 8

“Emotion and Design”
Don Norman says that attractive things work better. When something looks good, it makes us feel happy. This good feeling helps us be more creative and more patient if we have a small problem using the product. A happy user is a better problem solver.

I agree with this. A nice looking design, like a pretty website or a well made phone, is more enjoyable to use. It makes you want to keep using it. Good design is not just about being pretty. It is about making things work better by making the user feel good.

“Her Code Got Humans on the Moon”
Margaret Hamilton was a computer scientist who led the team that created the software for the Apollo moon missions. She did this at a time when there were very few women in her field. Her work was vital to landing astronauts on the moon and bringing them home safely.

I am impressed by how Hamilton planned for mistakes. She wanted to add code to prevent errors that everyone else thought would never happen. She was right. An astronaut later made one of those exact mistakes. Her story shows why it is so important to think about what could go wrong, especially on a big and important project. Good planning can prevent big problems.

Overall
Both readings show that the best designs think about people. Norman teaches us that a product that makes users feel good will work better. Hamilton teaches us that a system designed for human error is stronger and safer. Whether it is a teapot or a spaceship, thinking about the person using it is the key to good design.

W8: Creative Switch

Inspiration

 I drew inspiration from interactive toys and physics-based games where an object’s motion triggers an outcome. I wanted to create a setup where the physical action of dropping an object could directly influence the visual cues.

Concept

The idea is simple yet engaging: dropping a conductive ball into a cup lights up an LED. The cup contains two strips of conductive material that act as a switch. When the ball touches both strips, it completes the circuit, sending a signal to the Arduino, which then lights the LED. This concept transforms a small, physical action into a clear electronic response, demonstrating the connection between the real world and digital systems.

Implementation

To bring the concept to life:

I attached two strips of copper tape inside a cup, positioned on opposite sides so that the ball could touch both when dropped.

Wires were connected from the copper tape to the Arduino circuit: one to 5V, the other to a digital input pin with a pull-down resistor to stabilize readings.

The LED was connected to another Arduino pin with a series 10K ohm resistor to prevent overcurrent.

Finally, I wrote a simple Arduino code using digitalWrite to read the input from the cup and light the LED whenever the ball completed the circuit. This setup allowed the system to react instantly when the ball was dropped, making it interactive.

Pictures

fig 1: circuit schema

fig 2: circuit

Video Demonstration

Challenges

During development, several practical challenges arose:

Material availability: Initially, I planned to use Aluminum foil as the conductive ball but it was unavailable. I switched to copper as a complementary conductor, which worked well.

Maintaining electrical contact: Attaching wires to the copper tape and ensuring consistent contact was difficult. The wires would often become loose, causing the LED to light only at certain angles. To resolve this, I maximized the contact area between the ball and copper strips and reinforced the connection from the cup to the breadboard. This ensured reliable detection whenever the ball was dropped.

Future Improvements

A possible future enhancement would be to introduce multiple cups or targets, each connected to a different colored LED and sound output. For instance, when the ball drops into a specific cup, it could trigger that cup’s LED to light up in a unique color and play a corresponding sound. This would make the interaction more dynamic and visually appealing.

To make it more game-like, the cups could be arranged in a triangular formation, with each cup representing a different score or difficulty level. For example, the front cup might be worth fewer points while those at the back are worth more. The Arduino could then keep track of the scores based on which input pin was triggered, creating an engaging mini electronic scoring game.

Week 8: Reading Response

Norman’s ‘Emotion & Design: Attractive things work better’ was a great complimentary work to his ‘The Design of Everyday Things’ that we previously read this semester. A perspective that may seem contrasting was presented yet upon a closer look it becomes apparent that it is not an opposition to his previous work but a build up. Both the works tie in together to create the full picture of what the essential elements of design are. After reading his previous work, I’d say I definitely increased my focus and attention on functionality and usability in my work without considering the fact that  aesthetics wen hand in hand with them. A work that is appealing to look at is one that encourages attention and engagement with it, as human nature is to be driven by aesthetics and visuals, sometimes even beyond usability. Though that should not take away attention from the importance of usability, and that is why the puzzle is incomplete without the pieces provided by the previous work by Norman.

This work particularly brought to my attention the importance of positive affect in encouraging creativity and breadth of thinking when it comes to design and got me thinking of how I can contextualize this to my upcoming projects. Part of creative interactive art is to create works that encourage exploration of the themes and functionalities of a given work, and the achieve this desired effect while usability is essential to ensure that the users have guidance to what they need to do, it is as important to focus on aesthetics to encourage this exploration of the usability of the work. While the importance of positive affect is undoubtedly present in most designs, I’d say it’s importance is exceptionally present in the design of interactive art works and projects. Therefore, the discussion of the intersection of usability and aesthetic is an important one to present in the beginning stages of the design journey to have a foundation that is strong in both aspects. Though, I do believe that in certain cases usability might prove to be more essential to a project or vise versa due to the nature of the situation.

Further, McMillan’s ‘Her Code Got Humans on the Moon’ about the programmer Margret Hamilton was an inspiring work of the discussion of the career beginnings of a women that navigated her way through the field of software engineer back in it’s initial appearance. Beyond her impressive feat reading the work was interesting dive into the world of programming and engineering before it became what we know it today. The method of punching holes in stacks of punch cards to be sent to guide the threading of copper wires into magnetic rings was a clear indication of the significant progress in the field of software engineering. In particular, the lack of urgency of the use of error-checking code was another aspect that is extremely contrasting to today’s practiced with error-checking becoming a central part of today’s programming. Most systems now are responsible to the functions of so many everyday tasks and manage the flow of large amounts of data, which is why they cannot afford to face errors. Though, the article made it clear that mistakes such as the ones that happened with the Apollo were necessary to understand the importance of such functionalities. Which revealed the importance of the work that was being done by Hamilton and the rest of the team at the time to the foundation of today’s software engineering industry.

Midterm Project: An Unusual Case

Concept

An Unusual Case is a horror mystery game, inspired by escape rooms, where there are scattered clues around the game in each room, and the user will have to identify them to move on to the next room and solve the mystery. Else, they are forever trapped in the room. The concept aims for the user to both have an engaging and entertaining experience while thinking through the clues and pushing them to think outside the box. Focusing on the player’s problem-solving and creative skills. Clues never give away the answer directly, rather they push the player to apply critical thinking and pattern recognition.

To make the game even more engaging, the themes of the game visual design are darkness and the melancholy which tie in well with the color palette consisting of deep shadows and muted tones. The mood is further curated by the sound effects that go from very quiet background noises to loud and sudden jumpscares, a mix that is intentional to keep players on edge and engaged. This horror aspect is not just for the sake of enticing fear but also to pull the players into the emotional tension of the situation, thus making every choice and revelation feel more powerful. In the end, An Unusual Case has the ambition to be a combination of mental challenge, appealing story, and spooky atmosphere, giving players a very deep and engaging experience.


 

Code Snippet

draw() {
    // Perspective scaling for hallway
    let scaleFactor = 200 / wallDist;
    let w = wallSize * scaleFactor;
    let h = wallSize * scaleFactor;

    let cx = width / 2;
    let cy = height / 2;
    let left = cx - w / 2, right = cx + w / 2, top = cy - h / 2, bottom = cy + h / 2;

    // Draw hallway walls
    fill(20, 0, 0); noStroke();
    quad(0, 0, left, top, left, bottom, 0, height);
    quad(width, 0, right, top, right, bottom, width, height);

    // Fog effect
    this.fogAlpha = 40 + 20 * sin(millis() * 0.005);
    fill(0, 0, 0, this.fogAlpha);
    rect(width / 2, height / 2, width, height);

    // Door setup and glow animation
    let doorWfull = w / 3, doorH = h / 1.5;
    let doorX = cx, doorY = bottom - doorH / 2;
    doorBounds = { x: doorX, y: doorY, w: doorWfull, h: doorH };

    if (!doorOpen) {
        let elapsed = millis() - this.lastGlow;
        if (elapsed < 3000) this.glowAlpha = 60 + 40 * sin((elapsed / 3000) * TWO_PI);
        for (let i = 1; i <= 3; i++) {
            fill(255, 0, 0, this.glowAlpha / (i * 1.5));
            rect(doorX, doorY, doorWfull + i * 12, doorH + i * 12, 8);
        }
    }

    // Door animation and jumpscare trigger
    if (doorAnim > 0.01 && !this.jumpscareTriggered && doorAnim > 0.4) this.triggerJumpscare();

    // Player movement and sound
    let moved = false;
    if (moveForward) { wallDist = max(50, wallDist - 2); moved = true; }
    if (moveBackward) { wallDist = min(800, wallDist + 2); moved = true; }
    if (moved && !footsteps.isPlaying()) footsteps.loop();
    else if (!moved) footsteps.stop();
}
The Hallway.draw() function is something I am exceptionally proud of because it is the technical core of the game, where several systems meet to provide an engaging player experience. This function takes care of complicated animations like wall scaling to make the scene appear deeper, glowing door effects to attract the player, and fog shading for ambiance. It combines player movement, door collision detection, footsteps and door interaction sound effects, and even a jumpscare mechanism, all with smooth transitions and low latency bringing together the essence of the game.  It’s the moment when the player moves from curiosity to fear, which characterizes the game, and a quality that really binds An Unusual Case together. I’d say I spent a lot of time on it because it is the first scene and first impressions matter so I wanted a hallway that communicated the message of the game well through both aesthetic and functionality.

Embedded Sketch 

Game Design
The game is designed in such a way that the main elements are separated into classes where the game and the environment are organized at the same time. The Hallway class is the one in charge of rendering a perspective corridor for the main exploration area and controlling the movements of the players. Animations of the doors, glowing effects, jumpscare triggers, and other events are all part of the Hallway class’s responsibilities.

The wordGame class is a puzzle where the player needs to unscramble the letters to form the correct words in order to move ahead. This class is responsible for selecting the words to be scrambled, performing the scrambling, validating the input, displaying the result, and transitioning the player to the next room based on the success or failure of the player. Another module, FindObject, creates an interactive mechanic of search in darkness where the player using the flashlight effect looks for the hidden key, making the experience more fun and engaging. It uses the clipping effect of the flashlight, placement of the object, and cues for interaction.
The officeReveal class works up to a narrative turning point by presenting a final interaction between the player and a document that reveals the mystery’s resolution. It is responsible for various scene elements, such as rendering, glowing highlights, paper enlargement, and reveal transitions where the player has the option to restart. Last but not least, the Character class is in charge of the rendering, scaling, and positioning of the player’s avatar to ensure there is no visual discontinuity among the scenes.
Reflection
The process of organizing the code and making sure that all classes worked together perfectly was difficult but it also proved to be a great learning experience. The communication between the hallway, rooms, mini-games, and animations was difficult and took up a lot of time, especially when trying to keep transitions smooth and the functions consistent. This experience brought to my attention how we can integrate a lot of the techniques we learnt through readings into our work such as signifiers as I learnt through user testing where more visual assistance was needed in certain places. I see the potential in this project for future expansion, more levels, different types of challenges, and even improving the current ones, enriching the game and making it more captivating. I had such a great time creating this interactive experience and it has piqued my interest to keep working on it even after the class is over, through experimenting with the features, improving the design and making it a more complete and engaging mystery game.

Midterm Project: “Football Obstacle Game”

Concept:

The idea behind this project was to create an interactive football shooting game that combines skill, strategy, and dynamic difficulty. The player must shoot goals while avoiding defenders and a moving goalkeeper. The game incorporates increasing challenge as the player scores, adding both excitement and replay value.

I wanted the game to be simple enough for beginners to play, yet engaging enough to demonstrate programming concepts like collision detection, movement logic, and audio-visual feedback in p5.js

Design and features of the game:

  • Player Controls: Use the arrow keys to move and mouse click to shoot.

  • Dynamic Defenders: Start with 3 defenders; a new defender is added every time the player scores.

  • Goalkeeper: Moves horizontally across the goal area and tries to block shots.

  • Score Tracking: Displays the player’s score at the top left.

  • Audio Feedback: Crowd cheers when the player scores, and a whistle plays when the player loses.

  • Background Image: I used a football pitch background image to visually represent the field.

  • Collision Detection: The game detects collisions between the player, ball, defenders, and goalkeeper to determine goals or game overs.

Code Highlight:

One of my favorite code snippets is the restart logic. Instead of refreshing the entire page, pressing “R” instantly resets the player, ball, defenders, and score to allow for a smooth restart.

Another code snippet I’m proud of is the collision detection function. This function checks whether the player or the ball collides with any of the defenders using the distance formula. It calculates the distance between two objects and compares it to their combined radii — if they overlap, the game ends.

// Restart after lose
  if (gameState === "lose" && (key === "r" || key === "R")) {
      Ball1.reset(Player1);
      Player1.reset();
      score = 0;

      // Reset defenders
      defenders = [];
      for (let i = 0; i < 3; i++) {
          let defenderX = random(width / 4, (3 * width) / 4);
          let defenderY = random(height / 6 + 50, (5 * height) / 6 - 50); // release below goal
          defenders.push(new Defender(defenderX, defenderY, 3));
      }
function checkDefenderCollision() {
  for (let defender of defenders) {
    // Player collision
    let dPlayer = dist(Player1.x, Player1.y, defender.x, defender.y);
    if (dPlayer < 20 + 15) {
      loseGame();
      return;
    }

    // Ball collision
    if (Ball1.isMoving) {
      let dBall = dist(Ball1.x, Ball1.y, defender.x, defender.y);
      if (dBall < Ball1.radius + 15) {
        loseGame();
        return;
      }
    }
  }
}

Embedded Sketch:

This is a link to the sketch: https://editor.p5js.org/Jayden_Akpalu/sketches/_4tt_i0oG

Reflections & Future Improvements:

Through this project, I learned how to manage game states, implement collision detection, and integrate audio and visuals for a more immersive experience. I also improved my debugging and problem-solving skills — especially when aligning the goalkeeper, handling full-screen scaling, and ensuring the game reset logic worked correctly.

If I had more time, I would like to improve the game in several ways. First, I’d like to replace the simple circles used for the players and defenders with animated sprite characters. This will make the movement and shooting feel more realistic and visually engaging. For example, I could use a sprite sheet of a footballer running or kicking the ball, and animate it frame by frame when the player moves or shoots. Also, I’d like to add multiple levels of difficulty with new environments or faster defenders to make gameplay more dynamic. Finally, I’d love to create a high-score tracker, allowing players to save and compare their best performances.

Midterm Project; Operation: Campus Cat

Project Concept
Operation: Campus Cat is a fast-paced game inspired by the beloved community cats of NYU Abu Dhabi. Set against the backdrop of a stylized campus map, players must protect their food from a hungry, mischievous orange cat who roams freely and relentlessly across the scene. It’s a tongue-in-cheek interpretation of a very real situation many NYUAD students have experienced: trying to eat while a campus cat watches… and slowly approaches.

While planning this game, I intended to blend together light strategy, reflex-based mechanics, and playful visuals that are based on NYUAD’s. As you can see, he tone is humorous but is still grounded in campus life, and, quite frankly, don’t expec  a fantasy game about fighting cats, but rather a funny tribute to the cats who rule the Interactive Media garden and food court. Operation: Campus Cat aims to turn a slice of real NYUAD culture into an accessible, replayable p5.js browser game. So, if you happen to be one of our campus cats’ victims, if they stole your food, I hope this makes you feel better in some way!

How the Game Works
Well, the core loop is pretty simple: food spawns randomly on the screen every few seconds, and the player must reach the food before the cat reaches it. Each successful click earns 5 points. But if the cat eats a food item, the player loses 2 points and it adds to the “cat ate” counter. Once the cat eats 5 items in a round, or if the round timer hits 0, the player loses one of their 3 lives. Once all lives are gone, the game ends with a final score.

The cat’s movement isn’t passive; it actively chases the nearest food using simple vector math. It glides across the campus map toward its next target, making the player prioritize which items to save. Clicking on the cat itself instead of the food will make it temporarily disappear (a “Signal Lost” message appears in its place), but doing so costs 3 points. Imagine you’re using a satellite to track the cats’ movement. This is basically it! This mechanic creates a high-stakes trade-off: delay the cat briefly, or focus on clearing food? Rounds last 60 seconds, and the player must keep moving fast and making strategic decisions.

A full-screen responsive shows score, remaining lives (as hearts), the number of missed food items in the current round, and a countdown timer. The game also features a start screen, instruction screen, and a game over screen, with appropriate transitions and buttons to replay or restart the session.

 Code Snippet
Here’s the logic for the cat’s food-chasing behavior, which uses distance checks and angle math:

const angle = atan2(nearestFood.y - this.y, nearestFood.x - this.x);
this.x += cos(angle) * this.speed;
this.y += sin(angle) * this.speed;

The Food class includes a pulse animation using a sine wave to make items feel more alive and clickable:

const pulse = map(sin(frameCount * 0.1 + index), -1, 1, 0.85, 1.15);

The game is organized using object-oriented design. The core classes are:

  1. Game: Overall state manager (start, play, game over)
    2. Cat: Handles cat behavior, movement, hiding state
    3. Food: Controls food spawning, visuals, and interaction
    4. HUD: Manages the interface and gameplay data display
    5. Button: A reusable UI component for menus and controls

Assets like images and sound effects are loaded via the Assets object, with fallback logic in case of load failure (e.g., drawing simple shapes instead of broken images). This ensures that even with missing files, the game still runs and remains playable.

What I’m Proud Of

  1. Game’s background

    I made this in freshman year while taking a core design class here at NYUAD. When I was looking for a drawing that shows our campus from above, this one worked perfectly! The only thing that was time consuming about it was finding the right palette that is both relatable and playful to suit the mood of the game. I decided to make it more green, make the top of campus center to resemble/imply the head of a cat (not sure if it shows). As I said, choosing the colors was challenging, and so ChatGPT helped me with the color choice as well.
  2. One section of the code I’m particularly proud of is the pulsing animation inside the Food class. It’s a small visual detail, but it adds a lot of liveliness to the screen. Each food item subtly “breathes” using a sine wave function, making it feel dynamic and easy to spot. This animation helps guide player attention and makes the gameplay feel more polished.

    // Inside Food.draw()
    const pulse = map(sin(frameCount * 0.1 + index), -1, 1, 0.85, 1.15);
    const img = Assets.img.food[this.imageKey];
    
    if (img && img.width > 0) {
      push();
      translate(this.x, this.y);
      scale(pulse);
      imageMode(CENTER);
      image(img, 0, 0, this.size * 2, this.size * 2);
      pop();
    }
    

    This little animation uses sin(frameCount * 0.1) to smoothly oscillate each food’s scale over time, creating a soft pulsing effect. I like this snippet because it shows how much visual impact can come from just a few lines of math and thoughtful timing, no extra assets or libraries needed. It makes the entire game feel more animated and alive without adding any performance cost.

    Challenges & Areas for Improvement

    One of the biggest challenges was cat movement; initially the cat was too fast or too slow, or would teleport unexpectedly. I had to tune the speed and collision radius multiple times to make it feel fair. Similarly, I ran into trouble with image preloading: sometimes food items or the campus map would fail to load. I added fallback logic so that the game shows a colored circle if images fail.

    In terms of gameplay, it currently doesn’t scale difficulty; every round is the same length, and the cat moves at a constant speed. In future updates, I’d like to introduce progressive rounds where spawn intervals shorten and the cat gets faster. Other ideas include adding multiple cats, special food items, or power-ups like “cat repellent” or “freeze time.”

    Lastly, while the game runs in fullscreen and resizes on window change, it’s not yet optimized for mobile/touch input, which would make it more accessible to a wider audience. Touch support and gesture input would be a major next step.

Midterm Project- Panda Math Stack- Elyazia Abbas

Concept: Learning Through Play with Panda Math Stack

For my midterm project, I chose to integrate a simple math operation game into my p5 sketch.  The Panda Math Stack transforms simple arithmetic into an interactive adventure where learning meets play. Designed with cheerful visuals and smooth animation, the game combines the task of a running panda collecting pancakes to make math practice fun and rewarding. Players solve addition problems by catching and stacking pancakes that match the correct answer. With every correct answer, the panda celebrates as cheerful sound effects and background music enhance the sense of accomplishment.

The game’s 30-second timer adds excitement, encouraging quick thinking while keeping learners engaged. Beyond its playful surface, Panda Math Stack promotes cognitive growth, especially for kids, through repetition and visual reinforcement, showing that learning can be both joyful and challenging in the right balance of design, music, and motion.

Explanation of The Main Components:

1. Use of Sounds
Sound plays an important emotional and feedback role in Panda Math Stack. The game includes three primary sound effects: background music (bgMusic), a stacking sound (boinkSound), and a game-over sound (gameOverSound). The looping background track establishes an upbeat rhythm that keeps players engaged throughout gameplay. The short “boink” effect provides instant positive feedback every time a pancake successfully lands on the tray, reinforcing the satisfaction of correct stacking. Finally, the game-over sound signals the end of a round, helping players transition between play sessions. Together, these sounds create a responsive and immersive auditory experience that strengthens player focus and motivation.

2. Use of Shapes
Shapes in this project are used to render most visual elements directly in p5.js without relying on external images. Circles and ellipses form pancakes, clouds, and decorative symbols, while rectangles and triangles are used for UI buttons and the grassy ground. By layering and coloring these basic shapes, the design achieves a friendly, cartoon-like appearance. The pancakes themselves use multiple overlapping ellipses in different brown tones, giving them dimension and warmth. This approach demonstrates how simple geometric forms can produce visually appealing and cohesive game elements that maintain a light, playful aesthetic.

3. Use of Images for Sprite Sheet
The panda character’s animation is handled using a sprite sheet (panda.png or panda2.png), divided into multiple frames organized in rows and columns. Each frame represents a different pose of the panda walking or idle. During gameplay, the code cycles through these frames (currentFrame) to simulate movement. This sprite-based animation technique allows smooth transitions without heavy computation, making the character appear lively and expressive as it moves and interacts with falling pancakes. The use of images here contrasts with the drawn shapes, introducing a visually rich and character-focused element that enhances personality and storytelling in the game.

 

4. On-Screen Text Evolution
Text evolves dynamically to communicate progress and emotions to the player. At the start, large pixel-style fonts announce the title and instructions, creating a retro arcade feel. During gameplay, text displays math problems, timers, and feedback messages that change in color and size depending on correctness ( for success, for errors). In the end screen and notebook view, typography shifts toward clarity and encouragement, summarizing scores or reviewing mistakes. This continuous adaptation of on-screen text keeps information readable while reinforcing the game’s educational purpose — transforming numbers and feedback into part of the visual storytelling.

5. Object-Oriented Programming in notebook.js and pancake.js
Both notebook.js and pancake.js apply object-oriented programming (OOP) principles to organize behavior and state efficiently. The Pancake class defines how each pancake behaves — from falling physics (update) to visual rendering (show) — encapsulating movement, collisions, and display logic into self-contained objects. Similarly, the Notebook class manages data storage and visualization of wrong answers, using methods like addWrong(), display(), and drawStack() to handle user progress and draw interactive visual feedback. This modular, class-based approach makes the code easier to scale, reuse, and maintain, as each object represents a distinct component of the game world with its own properties and responsibilities.

Code I am Proud of:

function checkAnswer() {
  if (!roundActive) return;

  if (stack.length === targetStack) {
    // Correct number of pancakes
    correctRounds++;
    message = `✅ Correct! (${num1} + ${num2} = ${targetStack})`;
    messageTimer = millis();
    roundActive = false;
    setTimeout(() => newMathProblem(), 1500);
    if (boinkSound) boinkSound.play();
  } else {
    // Incorrect answer
    message = "❌ Try Again!";
    messageTimer = millis();
    let question = `${num1} + ${num2}`;
    notebook.addWrong?.(question, targetStack, num1, num2);
    stack = [];
    pancakes = [];
  }
}

The checkAnswer() function is the core of the game’s math logic — it checks whether the number of pancakes the player stacked matches the correct answer to the math problem shown on screen. When the player presses “Check,” the function compares the length of the stack array (how many pancakes were caught) to targetStack (the sum of num1 + num2). If they’re equal, the player’s answer is correct — their score (correctRounds) increases, a success message and sound play, and a new math problem appears after a short delay. If the count is wrong, an error message is displayed, the pancakes reset, and the player can try again, making this function the key link between the math challenge and interactive gameplay.

Through Beta Testing:

Through beta testing, I received valuable feedback from my friends, that helped shape the final version of Panda Math Stack. They suggested transforming the concept into a math-based problem-solving game rather than just a stacking challenge, as this would make it more educational and purposeful.

 

They also recommended developing the notebook feature to track incorrect answers, allowing players to review and learn from their mistakes after each round. Incorporating these suggestions not only improved the gameplay experience but also strengthened the project’s learning component, making it both fun and pedagogically meaningful.

Embedded Sketch:

Future Improvements:

For future improvements, I plan to expand Panda Math Stack by adding more playable characters with unique animations and personalities to make the experience more engaging and customizable. I also aim to introduce multiple levels of difficulty, where each stage presents new visual themes and progressively challenging math problems. In addition to basic addition, future versions will include other arithmetic operations such as subtraction, multiplication, and division, allowing players to practice a wider range of skills. These updates will transform the game into a more dynamic and educational experience that adapts to different ages and learning levels.

Midterm Report

My Concept

For the midterm, I created Highway Havoc, a fast-paced driving game where the player must weave through incoming traffic and avoid collisions while maintaining control at high speeds. My goal was to build an arcade-style driving experience that feels alive, unpredictable, and immersive. Cars rush toward you, radar traps flash if you’re speeding, and the scrolling environment creates a sense of depth and motion.

To make the gameplay feel as close to real highway driving as possible, I implemented several interactive and behavioral features:

  • Dynamic traffic flow: Cars and buses spawn randomly, sometimes creating congested traffic and other times leaving open gaps.
  • Lane-based speeds: Vehicles on the left lanes drive faster than those on the right, mimicking real traffic patterns.
  • Adaptive driving: Vehicles automatically slow down and match the speed of the car ahead to prevent crashes.
  • Autonomous behavior: Vehicles occasionally use turn signals for three seconds and switch lanes when the adjacent lane is clear of other NPC cars. They can still crash into the player to make the game more challenging.
  • Reactive NPCs: There’s a 10% chance that a vehicle will get “spooked” and change lanes when the player flashes their headlights.

Website: https://mohdalkhatib.github.io/highwayhavoc/

Embedded Sketch

 

How it works

The game is built using object-oriented programming to manage all its core components: Player, EnemyCar, SchoolBus, and several static environment classes like LaneLine, Tree, and Radar. To make the player car look like it’s going upwards, all the objects on the canvas move downwards depending on the difference between the player’s speed and the object’s speed. Timed progression is handled using millis(), allowing the game to dynamically scale its difficulty It begins with just two enemy cars and gradually increases to seven over time. After 30 seconds, a special SchoolBus class appears. This bus inherits most of its behavior from EnemyCar but acts as a larger, slower obstacle, adding variety and challenge to the gameplay.

Player movement is handled with smooth lerp() transitions instead of instant lane jumps, creating a realistic sliding motion. The car tilts slightly while switching lanes, giving the animation a sense of weight and momentum.

// Smooth lane movement
this.x = lerp(this.x, this.targetX, 0.15); // 0.15 is speed of slide

// Calculate tilt: proportional to distance from targetX
let tilt = map(this.x - this.targetX, -63, 63, 0.2, -0.2); // max tilt ±0.2 rad 

// Rotate car while sliding
translate(this.x, this.y);
rotate(tilt); 

 

The garage menu is implemented as a separate state in the program. All player cars are stored in a 2D array (matrix) where the first dimension represents car type and the second represents color variants. Selecting a car updates the active type index, and selecting a color updates the corresponding color index. The game then loads the pre-rendered image from playerCarImgs[type][color] for the main gameplay.

let playerCarImgs = [];
let carColors = [
  ["#f10a10", "#b77bc6", "#ffde59"], // Car 1 colors 
  ["#737373", "#302d2d", "#df91c1"], // Car 2 colors 
  ["#7ed957", "#6f7271", "#df91c1"]  // Car 3 colors 
];
let selectedCarIndex = -1;
let selectedColorIndex = 0;
let selectedColorIndices = [0, 0, 0]; // store each car's color choice
// Load player cars (3 types × 3 colors)
  for (let i = 0; i < 3; i++) {
    playerCarImgs[i] = [];
    for (let j = 0; j < 3; j++) {
      playerCarImgs[i][j] = loadImage(`player_car_${i}_${j}.png`);
    }
  }

 

From a design standpoint, I’m especially happy with how the visual composition is handled. The positions of all road elements (lane markers, trees, etc.) are responsive relative to the center of the road, ensuring that everything remains aligned even if the screen size changes. The gradual introduction of more enemies also creates a natural difficulty curve without overwhelming the player early on.

One of the features I’m most proud of is the radar system. It actively monitors the player’s speed and position. If the player passes a radar while exceeding the speed limit, the game transitions to a “game over” state. At that moment, p5 captures a snapshot of the player’s car beside the radar, displays it on the game over screen, and plays a camera shutter sound effect. Similarly, collisions trigger a crash sound, giving the sense of danger on the highway.

detect(player) {
      return abs(this.y - player.y) < 10 && playerSpeed > speedLimit;
}

if (radar.detect(player)) {
      gameState = "GAMEOVER";
      engineSound.stop();
      captureGameOver("You were caught speeding!");
      shutterSound.play();
}

// Crashed or caught by radar: take snapshot
let snapWidth = 900;
let snapHeight = 300;

let sx = constrain(player.x - snapWidth / 2, 0, width - snapWidth);
let sy = constrain(player.y - snapHeight / 2, 0, height - snapHeight);

gameOverImage = get(sx, sy, snapWidth, snapHeight);
gameOverMessage = message;

 

Problem I Resolved

One of the biggest challenges I faced was figuring out how to implement realistic car sounds that respond naturally to gameplay. My initial idea was to use separate audio clips for different speeds or for moments when the player accelerates or decelerates. However, this quickly became too complex and didn’t sound seamless in motion.

Instead, I switched to a single looping engine sound and mapped both its playback rate and volume to the player’s current speed. This made the sound naturally increase in pitch and intensity as the car accelerated, without needing multiple clips. To add more realism, I also added a short braking sound effect that triggers automatically when a large drop in speed is detected, simulating tire friction or skidding during sudden stops.

function handleInput() {
  if (keyIsDown(UP_ARROW)) playerSpeed = min(playerSpeed + 0.1, maxSpeed);
  if (keyIsDown(DOWN_ARROW)) {
    let oldSpeed = playerSpeed;
    playerSpeed = max(playerSpeed - 0.5, 0);
  }

  // Adjust pitch and volume of engine
  let volume = map(playerSpeed, 0, maxSpeed, 0.1, 1.0);
  engineSound.setVolume(volume);
  let pitch = map(playerSpeed, 0, maxSpeed, 0.8, 4.0);
  engineSound.rate(pitch);
}

// If the speed decreased by 5 or more within 1 second
if (speedDrop >= 5) {
      if (!brakeSound.isPlaying()) {
        brakeSound.play();
      }
}

 

Areas for Improvement

One issue I noticed is that enemy cars sometimes merge into the same lane at the same time, leading to overlapping or clipping. Improving their lane-changing logic to better detect other vehicles could make the traffic feel more realistic. I’d also like to expand the variety of vehicles by adding a larger collection of car models and giving each one unique attributes such as top speed, acceleration, and braking ability.

 

 

Midterm Project – Her Knockout!

Project Concept
For my midterm project, I wanted to create something that’s not only fun but also meaningful and personally significant. I wanted to focus on women’s empowerment, sports, and music—three areas I’m passionate about—and make a project that reflects these interests. My inspiration came from an essay I wrote in my FYWS class analyzing Nike’s “Dream Crazier” ad about women in sports (https://www.youtube.com/watch?v=zWfX5jeF6k4). From there, I decided to focus on MMA as the sport for my game. For the characters, I got them from Canva.

The game begins with the player choosing one of three female MMA characters, then moves into a gameplay section where the player can punch, kick, jump, and move to knock down negative comments. This is meant to symbolize the criticism and negativity that women in sports often face. But I didn’t want the project to end there; I also wanted it to educate. Inspired by typing challenge games like https://typetest.io/, I added a typing game that lets players learn MMA terminology while being entertained and challenged to type each fact correctly. This combination allows the game to be both meaningful and engaging.

How It Works
The game starts with an introduction screen where players can choose from three female MMA characters. Each character has a unique image and a short “thought” bubble that appears when clicked, adding a little personality to the selection. Once a character is chosen, the player enters the main gameplay stage. Here, you can move left and right, jump, punch, and kick to knock down flying negative comments. The goal is to clear enough comments to win, representing overcoming the negativity that women in sports often face.

To make the experience more engaging, I added an upbeat background music track that plays during the game, helping to set the energy and keep players entertained. In the typing game, I also included images for each MMA fact to make it more visual and less plain. These images were sourced from Google, and the music I used is “The Feeling (DNA Rework)” by Massano on SoundCloud. Combining visuals and audio adds another layer of immersion, making the game feel polished and lively.

After reaching a winning score, the game transitions into a typing challenge focused on MMA terminology. Players see a word or phrase with a matching image and must type it correctly. Correct answers earn points and trigger a confetti animation, while mistakes display “Wrong!”. The typing game continues until all the facts are completed, combining both entertainment and education. Through this process, I personally learned not only a lot about coding techniques like key press handling, animations, and typing effects, but also about MMA itself—its terminology, techniques, and the skill it takes to compete. The game also includes a restart function, so players can press “9” at any point to reset and start over, keeping it simple and practical.

What I’m Proud Of
I’m really proud of how I used the key press and input functions to make the game interactive and smooth. For example, movement, punching, and kicking are all tied to specific keys, which allows the gameplay to feel responsive and intuitive. I also made the negative comments move in a dynamic way, so the player has to actively engage with the game rather than just stand still.

Another thing I’m proud of is the combination of gameplay and learning. The transition from the action-based MMA game to the typing challenge was a design decision I think worked well. It keeps the player engaged, reinforces learning about the sport, and adds a sense of progression. I also like the small touches, like character thought bubbles, confetti effects, and the animated victory dance, which make the game feel lively and rewarding.

Code I’m Proud Of
I’m especially proud of this part because it implements a smooth “typing effect” for the characters’ thought bubbles:

function drawThoughtBubble(x, y, textContent, charObj) {
  textSize(width / 60);
  let padding = 20;
  let maxWidth = 300;

  // update typing
  if (charObj.displayedLength < textContent.length) {
    charObj.displayedLength += typingSpeed;
    if (charObj.displayedLength > textContent.length) charObj.displayedLength = textContent.length;
  }

  let displayText = textContent.substring(0, charObj.displayedLength);

  let words = displayText.split(' ');
  let lines = [];
  let currentLine = '';

  for (let word of words) {
    let testLine = currentLine + word + ' ';
    if (textWidth(testLine) > maxWidth) {
      lines.push(currentLine);
      currentLine = word + ' ';
    } else {
      currentLine = testLine;
    }

Each word appears gradually using the displayedLength variable, which keeps track of how many letters of the full sentence have been shown. By increasing this number frame by frame, the text “types itself” on the screen instead of appearing all at once, creating that dynamic typing effect.

I also implemented automatic line wrapping, which means that when a line of text gets too wide for the bubble, it automatically moves to the next line. To do this, I check the width of each line using the textWidth() function. This calculates how wide a piece of text will be on the canvas in pixels, letting me break lines before they overflow the bubble.

To calculate the height of the bubble and make sure the text fits neatly, I used  textAscent and textDescent. These functions tell you the distance the text reaches above and below the baseline, respectively, so by adding them together for each line (and including some padding), I could make the bubble the right size for any number of lines.

Finally, I added a small tail to the bubble with simple ellipse() shapes, giving it a classic comic-style speech bubble appearance. Combining all these elements was tricky but worth it. It ensures that the text always looks clean and readable on the screen, adding personality to the characters and making the game feel more polished and interactive.

Areas for Improvement
While the game works well overall, there are a few areas I’d like to improve. For one, the instructions could be clearer for the player, especially for the controls and how to transition between the punching/kicking game and the typing game. It would also be nice to give the user more options to explore, such as an on-screen button to mute the music, or the ability to navigate directly to either game from a menu without having to restart the whole experience. Adding more interactivity and choices could make the game feel less linear and more engaging, encouraging players to experiment and spend more time exploring the content.

Problems I Ran Into

One of the biggest challenges I faced was merging the different sections of the project into a single p5.js canvas. Initially, I had each part—the intro screen, the punching/kicking game, and the typing game—running in separate sketches, and I thought combining them would be straightforward. In reality, it was tricky to adjust all the positioning, scaling, and interactions so everything fit together smoothly. Because of this, I had to change the design of the typing game to make it easier to merge with the other parts. I spent a lot of time tweaking variables like character positions, text alignment, and animation effects to ensure the full project worked as one seamless game. It was a slower process than expected, but I’m proud that I managed to unify all the parts into a playable and polished experience.

(Here, I’ll include a screenshot of the previous version of the typing game to show the original design before I changed it for merging.)

Midterm Project – Jedi’s Revenge

Link to Sketch: https://editor.p5js.org/ma9331/full/ZSQDV21v5

Concept

For my midterm project, I decided to make it Star Wars-themed. The main character of the game is Luke Skywalker, who is on a mission to defeat the Galactic Empire. Luke is on the Death Star (the enemy’s base), where he encounters countless Stormtroopers whom he needs to defeat.

Instead of having a main objective to achieve, I made it a score-based game. In this one-player game, the user plays as Luke Skywalker and slashes as many Stormtroopers (enemies) on the ship before the timer runs out and gets their score at the end.

 

Process

This is my initial sketch which ended up being pretty similar to the final game’s outcome. The Stormtroopers emerge from the far right side of the screen and move towards the other end of the screen. Luke moves using the arrow keys and attacks by holding the “e” key.

I made two separate classes: one for Luke (the player) and one for the Stormtroopers (NPC enemies). Luke has a constant speed but the Stormtroopers have a random speed to make it a bit more challenging.

 

Code I’m Proud of

//initial/starter enemies
  new Stormtroopers(windowWidth, windowHeight * 1.2, scale, enemies);
stormtroopers.push(
  new Stormtroopers(windowWidth + 200, windowHeight * 1.2, scale, enemies)
);
function spawnEnemies() { //respawn function
  stormtroopers.push(
    new Stormtroopers(windowWidth, windowHeight * 0.8, scale, enemies)
  );
  stormtroopers.push(
    new Stormtroopers(windowWidth - 10, windowHeight * 0.8, scale, enemies)
  );
}
if (stormtroopers[i].x < -10) { // enemies go offscreen
  stormtroopers.splice(i, 1); // remove from array once offscreen
  
  if(score>0){
    score -=10; // decrease score, keep >= 08
  }

I had a lot of issues with the enemies spawning and positioning. At first, only a few enemies would spawn at the start of the game but would not respawn. This was because i set the Stormtroopers to stop walking at x=0, so they could never reach less than x=-10 and trigger the respawn function. I had to experiment with different values because the first enemies spawn as soon as you click run (because they’re in the function setup), so their positioning in fullscreen was different from the ones that respawn after. Ultimately, the Y-positioning for the initial enemies had to be windowHeight*1.2, and for the respawns it had to be set to windowHeight*0.8 in order for it work on fullscreen, and to be in the same Y-position as the initial enemies.

 

Design

For the end screen in my game, I took inspiration from the title screen at the start of every Star Wars movie.

This is what my end screen looks like:

And this is the title screen from Star Wars films:


I thought it would be a really cool but simple nod to the movies.

Areas of Improvement

If I had more time, I would’ve experimented more with the Stormtroopers’ abilities and gave them their own attacks: one attack could be that they shoot the player from their guns and deal damage to the player. Also, I had the thought of adding a health bar for both Luke and the enemies to make the game a bit harder (killing the enemies would require more than just one slash) and not time-based.