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.

PhotoboothMidterm Project

Concept:

For my project, I wanted to recreate that nostalgic, slightly awkward fun of using a photo booth, but in a digital, interactive way. The idea was to make something playful that still feels personal, where you type your name, pick a filter and a frame, and get a “thank you” screen at the end, almost like a real booth session. It’s simple, but it captures that small moment of anticipation and result. From entering your name to seeing your face appear across different frames and filters, I wanted it to feel like a sequence, a mini experience rather than just a photo being taken.

I was inspired by the photo booths you see at malls, the kind people use with friends, but I also wanted it to reflect me a little more. Since I love using my digital camera, I leaned into that and made it more camera-oriented, blending that nostalgic booth feel with something that connects to my own personality and interests. 

What I’m Proud of:

Not to toot my own horn, but I’m proud of various aspects of this project. I’ll start with the more design-oriented aspects, then get to the more technical parts.

For the frames, I originally wanted to use these camera frames on pinterest but I found the resolution to not be optimal so I decided to just make it myself using Canva. For reference, here’s a Pinterest frame and mine side by side. 

I decided on only three frames just to make the user experience notfeel overwhelming, but would love to add more in the feature.

Another design aspect I’m proud of is the flow of which the project goes. The path from one screen to another makes for a simple yet effective way to guide the user through the experience.

Now for the technical! There’s quite a few so I will narrow it down to my top 3. 

Firstly, this could count as design but setting a current screen variable made testing out different screens so much easier, without having to go back to the beginning everytime. It felt like a shortcut.

Secondly, when the project goes from one screen to the other, some features stayed and overlapped with features from the currents screen so learning when to show and hide was interesting and made me learn how important order is with code (even more than before). I think getting the hang of hide and show is very important for big scale project so I’m glad to have learnt it through this project.

Lastly, fitting the video feed to the frame. This might’ve been the second most difficult thing I had to deal with just because when I was looking at different ways to fit the feed into a frame, mostly by consulting chatGPT, it kept making me think that I had to look at the type of picture and make part of it transparent, and when that didn’t work, I was thinking of just doing it manually which is where frameData came from.

//define video feed positions per frame
//this lets us fit the live video inside each frame nicely
const frameData = {
 camera1: { x: 355, y: 249, w: 635, h: 440 },
 camera2: { x: 255, y: 245, w: 650, h: 480 },
 camera3: { x: 253, y: 215, w: 730, h: 530 },
};

So for every frame, it set the position and size for the feed.

Areas of improvement:

While I really wanted to use FaceMesh from ml5.js and had originally planned to draw a little red circle on the user’s nose when a face was detected, I couldn’t get it to work properly. I spent a huge amount of time debugging, revisiting documentation, and even consulting AI for help, but it kept interfering with my video feed in unpredictable ways. Eventually, I decided to set that idea aside for now, not because I don’t want to do it, but because I want to do it right.

In the future, I’d also love to add more frame options and maybe even a way for users to design their own frames. I imagine a simple drag-and-drop system where they can choose shapes, colors, or even add text onto the live feed. 

Overall, I really enjoyed working on this project. I think being from a coding background definitely helped me approach it with less hesitation, especially when dealing with the logic and structure. But I also found myself overflowing with ideas and not enough time to bring them all to life, which was both exciting and frustrating. In the end, I’m proud of how it came together. It feels playful and functional, and I think that balance is what makes it work.

References:

I used ChatGPT to debug for the most part, and used the ml5.js documentation when I was attempting to implement face detection to draw a circle on the nose.

P.S. I don’t have the sketch embedded since I worked on the project in VS Code instead of the online p5 editor, but here’s the GitHub website link: https://kzeina.github.io/Photobooth/ .

Midterm Project – Floral Frenzy

Overall concept  

Floral Frenzy is an original design experience which seeks to tap on the emotional responses of the users. Unlike other video games, there is no “winning” or “losing”. Instead, this project relies on the exploration and curiosity of the individual, as well as offering a visually pleasing experience.

The initial ideas consisted of creating a background with multiple static elements, such as mountains, trees, and bushes, and only a few interactive objects that would contain multiple functions. However, after some trial and error, this plan shifted and I decided to add more objects with interactivity in order to balance the weight of static vs interactive.

This was the initial sketch for the project, mainly focused on the aesthetics and potential elements to include in the final draft.
How does the project work 

From the spaceships, floating stones, and blue trees to the massive fantasy-like structure, this project consists of a mystical, otherworldly plane, drawing the user’s attention from one point to another. Nonetheless, the roses are meant to be the main focus of interactivity, as each of these contain a different reaction, such as releasing a symphony, displaying text, or displaying an unexpected result. Nonetheless, in order to produce the illusion of failure and success, two of the roses are programmed to either poison or compliment the user.

Overall the end result is a game-like set of visuals in which the user is given the instructions to interact with the object, these being the roses, and press a single key in order to delve into the real experience filled with animations in the background, vibrant colors, elements of a variety of sizes, and the interactive objects. Two of these objects provide different outcomes which then take the user back to the homepage.

Fullscreen Mode Sketch 

Link to sketch: https://editor.p5js.org/imh9299/full/HPfU68QCi

Embedded sketch:

Favorite code snippets

Although it appears to be a simple, clear function and codes at first glance, it took me many hours to decipher how to make the music, text, change of color, and other reactions to activate whenever the user clicked on them. Nevertheless, once it proved to be operational, I was filled with joy and I was proud to have completed it successfully, especially since this is the main interactive attraction of the project.

function mousePressed() {
  // helpful debug print
  print('mousePressed at', mouseX, mouseY, 'gameState:', gameState);

  // Only win/lose while the game is playing
  if (gameState === "playing") {
    if (winningRose.contains(mouseX, mouseY)) {
      print("clicked winningRose");
      wonGame = true;
      gameState = "end";
      return; // stop further handling this click
    }

    if (losingRose.contains(mouseX, mouseY)) {
      print("clicked losingRose");
      wonGame = false;
      gameState = "end";
      return;
    }
  }

  // Other clickable objects (always checked)
  if (flower.contains(mouseX, mouseY)) {
    print("clicked flower");
    song.play();
  }

  if (messageRose.contains(mouseX, mouseY)) {
    print("clicked messageRose");
    displayText = !displayText;
  }
}

Another code I am very proud of is the one that allows my cut image of a rock float in the background. At the start, I had to introduce all the variables such as the image, the preload function, fixing the size, speed at which it moved, tracking the time, among other things. While this wasn’t the most difficult codes to understand, it took me a while to find a way to transfer them from a clean, almost empty sketch to one filled with more than one hundred codes. Not to mention, once I managed to implement this code, I found myself struggling to make the music in one of my objects play again. Nevertheless, it was worth the effort as I like how this simple animation adds a new layer of life, along the moving spaceship and fantastical creature,  compared to the rest of the composition.

let rockX, rockY; // Position of background rock
let amplitude = 20; // How far up and down the rock moves
let speed = 0.04; // How fast the rock bobs
let time = 0; // A variable to track time for the sine wave
let rockImage; // Image of the rock

 

// --- ROCK ANIMATION (only in game) ---
let yOffset = sin(time) * amplitude;
let currentY = rockY + yOffset;
image(rockImage, rockX, currentY, 160, 160);
time += speed;

 

Areas for improvement and obstacles along the way

Some of the major obstacles I ran into was the integration of interactivity to the sketch. While I managed to build the necessary functions, classes, and parameters to apply interactivity for the sounds, text, and other responses, embedding these into my designed objects proved to be far more challenging than I expected. Not only did these responses have to activate as a result of the interaction of the user, but they also had to be contained within the “game-like” structure of the sketch. Furthermore, fixing the position of these objects, along the non-responsive ones, also forced me to explore multiple x and y positions so that the objects, images, and all additional elements could adapt to the windowWidth and windowHeight. Finally, after solving the issue of merging interactivity with the objects, finding a way to assemble Game states and the transitions between start, playing, and end states turned out to be a difficult challenge. Given that my project was specifically designed to be explored and simply be “visually pleasing”, integrating a game-like structure meant finding an end result that would match my project’s story and tone, and remain original. Despite all the struggling, after many hours of exploring and researching the p5 references, libraries, and works done by students in the past, I managed to overcome all these obstacles and offer this final product which I am genuinely happy about.

Some areas of improvement I would like to work on my next project would be the use of interactivity. Although I did include interactive objects, these are not as impressive as I initially thought. I would like to challenge myself to create a more interactive and engaging element such as the games designed by my peers, not only for my assignments but to also implement in my future non-academic works. Furthermore, I would like to learn how to make my codes look “cleaner” and make functions and classes in a way that reduces my stress when I need to find a specific code.

References:

Images: Rocks, Spaceship, and Fantasy structure were downloaded from Pinterest. The fantasy creature is an original design

Mouse press: https://drive.google.com/drive/u/0/folders/1Qx5kltRZwxzt7Z6l-G-mabzWDUs7nLgj

Elements: https://p5js.org/reference/p5/p5.Element/

Ai overview displaying text through an object: how to display text when clicking an object p5

Window width height example by professor Aya: https://editor.p5js.org/mangtronix/sketches/t4G0erH1B

Text Font: https://p5js.org/reference/p5/textFont/

Mirror image: https://editor.p5js.org/icm4.0/sketches/ETcm93Ua1

Float: https://p5js.org/reference/p5/float/

Used ChatGTP to clean my codes, (also to store and recover them since I suffered from constant glitches that deleted my information), and to find errors in my work whenever a specific element was not showing or it wasn’t processing its intended objective.

Midterm Project: “Save Polar Bear from Climate Change”

Fullscreen sketch

Overall Concept:

“Save Polar Bears” is a game designed to raise awareness of the impacts of climate change on the ecosystem of polar bears. It is an interactive game yet educational in a sense that it teaches you the real ongoing situation for polar bears. The reason why I made this game is I’ve been super passionate about climate change and I love polar bears since I was a child. I have been doing research about climate change since high school and I found out that polar bears are struggling with hunting due to the melting icebergs. Thus, I incorporated this situation as a main theme of this game: polar bears need to eat as many fish as possible to survive while running away from melting icebergs. 

How my project works: 

My game is simple. The user’s mission is to collect as many fish as possible without falling into the ocean. The field is made of a 10 X 10 grid representing icebergs. One of the icebergs is randomly chosen every 3 seconds to melt. But here is the tricky part that I’m proud of: every 2 seconds, the temperature increases, as shown in the top-left corner by the temperature parameter. The higher the temperature becomes, the faster the icebergs melt. However, there is also a power-up that appears every 7 seconds. If you pick it up, two icebergs will be restored. So, users have to figure out how to collect as many fish as possible while also restoring icebergs at the same time. 

 

Users can also learn about why we need to save polar bears from climate change by selecting the “Why Save Polar Bears?” button. I wanted to include this feature to educate people about the real situation affecting polar bears and their ecosystem due to the impacts of climate change.

The part of the game design I am proud of:

The part of the game design I’m most proud of is the gimmick where, as the temperature rises, more icebergs start to melt. I wanted to create a feature that reflects the real effects of climate change on the ecosystem of polar bears, and the idea of rising temperatures causing ice to melt felt the most meaningful and engaging to me. It represents what is happening in the Arctic Ocean, where polar bears are struggling to hunt their prey due to the rapid melting of icebergs.

 

The problems I ran into & Future improvements: 

The most challenging problem I ran into during the production of this game was definitely adjusting everything to full-screen mode. Since I am using 10 X 10 grids, it is not very suitable for a full-screen game, especially if you are using a laptop with varying screen sizes. Therefore, I had to calculate everything to make it fit properly in full-screen mode. For instance, I had to make the polar bear slightly larger when using full-screen mode by including fullscreen() in the if statement and multiplying the polar bear’s size by 1.4. I also had to resize each button depending on if users are in fullscreen mode or not using a ternary operator. But, I was able to learn how to use a ternary operator instead of using if statements again and again, so it was a good learning experience for me to make the code more readable. 

 

In terms of future improvements, I would like to add more interactive features to the game. For example, I was planning to include a feature where polluted garbage is scattered around the field, and if the polar bear collects three pieces of garbage, it dies. However, since I didn’t have enough time to implement it this time, I would like to add that feature later to incorporate more elements related to climate change. Furthermore, in terms of implementation details, since I had to manually calculate the sizes of the polar bear, fish, power-ups, etc., to match the full screen, I would like to adjust them more precisely next time to improve the user experience. Currently, if you touch the tip of a melted iceberg, it immediately results in a game over. I want to modify this so that players can slightly touch the edge of melted icebergs without immediately losing, as it can be confusing when they feel they didn’t actually fall into the ocean but still lose the game.

 

The part of code I’m most proud of: 

The part of the code that I’m most proud of is the GameManager class. This is the core of how the game works. It contains the addFish() function, which makes fish appear at random locations and adds them to the fish array for display. It also includes the addPowerups() function, which works similarly to addFish(). Furthermore, the fillWithIcebergs() function creates 10  X 10 grids by precisely calculating the position of each iceberg using the nested loops we learned in class. 

 

I also spent a lot of time designing the isOver() function, which is the core mechanic of the game. It checks whether the polar bear has stepped on a melted iceberg. To determine whether an iceberg has melted, I created a Boolean variable called melted to indicate which ones are completely melted. In the isOver() function, I used an if statement to only check the melted icebergs and added a condition where, if the distance between the polar bear and the iceberg becomes shorter than half the size of either, the game ends. I still need to fine-tune this logic so that small touches on the melted icebergs are allowed, making the game a bit more forgiving. 

class GameManager {
  constructor() {
    this.score = 0; //score starts with 0
    this.icebergs = [];
    this.fish = [];
    this.powerUps = [];
  }

  //function to fill up the canvas with 15 X 15 grids
  fillWithIcebergs() {
    let cols = 10;
    let rows = 10;
    let x_width = width / cols; //how wide each grid is
    let y_height = height / rows; //how tall each grid is

    this.icebergs = [];

    //create 15 X 15 grids
    for (let i = 0; i < cols; i++) {
      for (let j = 0; j < rows; j++) {
        //push all the icebergs into an array called icebergs to display them
        this.icebergs.push(
          new Iceberg(
            i * x_width + x_width / 2,
            j * y_height + y_height / 2,
            x_width,
            y_height
          )
        );
      }
    }
  }

  //function to restore 3 icebergs
  addIcebergs(num) {
    let restored = 0;
    for (let iceberg of this.icebergs) {
      if (iceberg.melted && restored < num) {
        iceberg.restore();
        restored++;
      }
    }
  }

  //function to add more fish
  addFish(num) {
    for (let i = 0; i < num; i++) {
      let x = random(width);
      let y = random(height);
      this.fish.push(new Fish(x, y, fishSprites));
    }
  }

  //function to add more powerups
  addPowerUp(num = 1) {
    for (let i = 0; i < num; i++) {
      let x = random(width);
      let y = random(height);
      this.powerUps.push(new PowerUp(x, y));
    }
  }

  //function to check if bear went into melted icebergs
  IsOver(bear) {
    //adjust the size of polar bear accordingly
    let bearSize = width * bear.baseScale;
    if (fullscreen()) {
      bearSize *= 1.6;
    }
    //don't make polar bear too big or too small
    bearSize = constrain(bearSize, 90, 300);

    const bearHitbox = bearSize * 0.5;
    const bearHalf = bearHitbox / 2;

    for (let iceberg of this.icebergs) {
      if (iceberg.melted) {
        const overlapX = abs(bear.x - iceberg.x) < bearHalf + iceberg.w / 2;
        const overlapY = abs(bear.y - iceberg.y) < bearHalf + iceberg.h / 2;

        if (overlapX && overlapY) {
          return true;
        }
      }
    }

    return false;
  }
}

This is the final production of my project:

 

Reference: 

In this midterm project, chatGPT was used to help me rectify several problems I faced during the development phase. Here is a breakdown of how I used chatGPT in this midterm project: 

    • ChatGPT helped me understand how to use a lambda function to carry out a certain action, which in my case switching the game state, when a certain button was pressed.
    • ChatGPT helped me adjust the size of objects (polar bear, fish, powerups, and icebergs), text (title and body paragraph), and buttons to adjust to the fullscreen mode. 
    • ChatGPT helped me calculate and adjust the position and size of the score display and the temperature slider at the corner of the game

Midterm Project

Concept

Color Gate Challenge is a fast and colorful reaction game where the player controls a glowing ball that changes colors to pass through matching gates. The idea came from color-matching and reflex games I used to play, but I wanted to create something that feels more modern and bright, with glowing effects and smooth motion.

The goal of the game is to move the ball through falling gates without hitting the walls. Each gate has a color, and the player must change their ball to the same color to pass safely. If you pass the wrong color or crash into the barrier, the game ends.

My Final Game:

Code Snippet and Parts I Am Proud Of:

One of the parts I am most proud of is how I  control the player, the gates, and the full game system.
Each part of the game (player, gate, and main game) is built as a class, which made it easier to add new features later.

The player’s color can change, and the game checks if it matches the gate’s color before letting the player pass. This made the logic clear and fun.

if (this.player.checkCollision(gate)) {
this.gameOver();
return;
}

This simple check controls the whole challenge of the game.
If the player touches the wrong color or hits the gate walls, the game ends immediately.

I also added a color preview system that shows the next few gate colors, so the player can plan ahead.
It uses small color dots on the screen to help the player see which color to switch to next.

this.upcomingGates.forEach((gate, index) => {
const dot = document.createElement('div');
dot.className = 'color-dot';
dot.style.background = this.getColorString(this.player.colors[gate.color]);
colorPreview.appendChild(dot);
});

Another part I am proud of is how the speed control works. The player can press keys to make the gates fall faster or slower, and there is a live bar that shows the speed level. This made the game more interactive and customizable.

Problems and Future Improvements

At first, the game was too easy because the gates were falling too slowly, and it didn’t feel challenging. I changed the gate speed and added random colors to make it more unpredictable and exciting.

Another problem was keeping everything in the right position when resizing the window. I had to fix the player’s size and position every time the screen changed, using the windowResized() function.

In the future, I want to:

  • Add special gates that move sideways

  • Add sound effects for color switches and collisions

  • Add power-ups that give the player a shield or slow motion

  • Create a moving space background for more depth

  • Add more visual effects like explosions and particle trails

Midterm Project – Chic & Click

Concept:

Chic & Click is an interactive dress-up game where players create stylish outfits by mixing and matching hats, tops, and skirts on a mannequin. The project is inspired by the dressing games I loved playing as a child, which sparked my interest in fashion and interactivity. Before building the game, I researched similar games and gathered references to refine the concept of changing outfits, making sure that each clothing piece fits properly and looks visually appealing (I attached the inspiration image below). The mission of the game is to provide a fun and creative experience that allows players to explore their personal style. Interactivity is at the core of the game: players click on the hat, top, or skirt areas to cycle through clothing options, accompanied by audio feedback and visual effects like neon glows and a camera flash when taking a photo of their final outfit. 

Inspiration from the dressing game:

Sketch:

Link to the sketch: https://editor.p5js.org/Aizhan/sketches/h5QYwQTMS

Key Elements of the Game:

Starting Page:
The game begins with a clean and minimalist start page designed to be visually pleasant, using pastel and calm colors throughout the game. On this page, players see the game cover and instructions, along with a “Start” button. When pressed, it transitions to the main playing page. The background image was designed using a ChatGPT image generator, while the button is created using shapes and text. The game can also be played in full-screen mode by pressing the “F” key, providing a bigger and more immersive experience.

Playing Page:
On the playing page, players can interact with the mannequin to change outfits. The clothing items—hats, tops, and skirts/pants were designed in Canva, with five options for each category, giving a total of 15 different clothing pieces. When a player clicks on a clothing area, they can go through the different options, and after the fifth item, it loops back to the first. The clothes come in various colors and styles, and each click plays a game click sound, making the game more engaging and interactive.

Result Page:
After clicking the “Finish” button, the chosen outfit is displayed on a result page with a photo studio background. A fun gaming song starts playing as the page appears, creating a celebratory mood. This page includes a “Take a Photo” button,  which triggers a camera sound, a visual flash effect, and automatically downloads the screenshot to the user’s computer as “MyOutfit.png.” This allows players to save and share their styled outfits. The second button of the page is “Finish”, and as the users press the button, they move on to the next page.

Restart Page:
The restart page thanks the player for playing and provides a “Restart” button. The background image remains consistent with the aesthetic of the game, maintaining the calm pastel theme, and allows players to start a new round of outfit creation easily.

Code snippet and parts I am proud of:

I am proud of how I implemented the camera effect and photo feature. The flash effect combined with the screenshot download feels polished and gives the game a fun feeling To be honest, this was a last-minute addition, as I initially only had music and the background. The p5 references and tutorials really helped me bring it to life.

// Camera Effect
function drawCameraEffect() {
  let elapsed = millis() - flashStartTime;
  if (elapsed < 500) { // flash lasts 0.5 seconds
    fill(255, 255, 255, 150);
    rect(0, 0, width, height); // semi-transparent overlay
    image(cameraImage, width / 2 - 450, height / 2 - 400, 900, 750); // display camera overlay
  } else if (showFlash) { // save screenshot after flash ends
    saveCanvas(cnv, "MyOutfit", "png");
    showFlash = false;
  }

I am also proud of how I handled the clothing interactivity. Using arrays and a simple .next() function to cycle through hats, tops, and skirts kept the code clean and easy to manage, while keeping the gameplay smooth and responsive.

// Clothing class 
class Clothing {
  constructor(images, offsetX, offsetY) {
    this.images = images;       // array of clothing images
    this.offsetX = offsetX;     // array of X offsets for each image
    this.offsetY = offsetY;     // array of Y offsets for each image
    this.current = 0;           // index of the currently displayed clothing
    this.show = false;          // whether to display this clothing
  }

  // Loops back to the first item after the last one
  next() {
    this.current = (this.current + 1) % this.images.length;
  }

  // Display the current clothing item on the canvas
  display(x, y, w, h, extraOffsetY = 0) {
    if (this.show) { // only draw if show is true
      let img = this.images[this.current];
      let aspect = img.width / img.height;       // maintain aspect ratio
      let targetW = w;
      let targetH = targetW / aspect;
      let offsetX = this.offsetX[this.current] || 0; // use offset for proper alignment
      let offsetY = this.offsetY[this.current] || 0;
      image(img, x + offsetX, y + offsetY + extraOffsetY, targetW, targetH);
    }
  }
}

I was also inspired by other students’ work to add neon hover effects on the buttons, which were fun to code and added polish without making the program more complicated.

function applyNeonEffect(btn) {
  let x = btn.x, y = btn.y, w = btn.width, h = btn.height;
  
  // Check if mouse is over the button
  if (mouseX > x - 20 && mouseX < x + w + 20 && mouseY > y - 20 && mouseY < y + h + 20) {
    // Apply neon glow effect
    btn.style("box-shadow", "0 0 10px #fff, 0 0 20px #fff, 0 0 30px #fff, 0 0 50px #fff");
  } else {
    // Remove glow when mouse is not over
    btn.style("box-shadow", "none");
  }
}

Problems/Future Improvements:

One of the most difficult parts of this project was getting the clothes to fit correctly on the mannequin. Each clothing image had a different size and shape, so I spent several hours trying to align them properly. At first, it was tricky because using the same coordinates for every clothing item caused them to look off. I solved this by creating offset arrays for X and Y positions for each clothing item. For example, topOffsetsX, topOffsetsY, skirtOffsetsX, skirtOffsetsY, and hatOffsetsY allowed me to manually adjust the position of each item so it would sit correctly on the mannequin.

Regarding future improvements, I would focus on a few key areas. One of them would be adding more clothing options and categories, like shoes, accessories, or jackets, would give the game more variety and customization. I could also implement a drag-and-drop feature so users can position clothes more freely instead of just clicking to cycle through them. Overall, this project was a great way for me to combine coding and design. I learned how to manage interactive elements, solve alignment issues, and create a smooth user experience.  It also improved my problem-solving skills, especially when dealing with image alignment and user interactions. This midterm game gave me a better understanding of how design and programming can come together to create an engaging user experience.