Hello Kitty’s Adventure: The Car Dodging Challenge
I chose this project because for my midterm, I created an experience and for my final, I aimed to challenge myself by creating a game. Additionally, having received my license two months ago, it seemed like the perfect opportunity to develop a game involving cars.
This game, titled “Hello Kitty’s Adventure: The Car Dodging Challenge” lets you control a character resembling Hello Kitty, guiding her left and right to avoid colliding with cars. As you skillfully maneuver past every four cars, the game progresses to a new level, increasing in speed. Your score accumulates with each second you survive. This fun and engaging game is inspired by my long-time fondness for a character similar to Hello Kitty, which has been a favorite of mine since childhood.
P5 Structure : IMG_5852
How the Game Works : IMG_5846
prototype + Schematic (ultrasonic distance sensor, two LEDs) :
Exhibition
The Im showcase on Friday 15th was a blast! It was my first time being part of an exhibition and making a game, which turned out to be super fun. I really enjoyed it, especially chatting with people there. I got loads of compliments and comments on my project, like “Your project was the best,” “Did you make this? It’s amazing,” and “This game is addicting.” It feels great to see my hard work pay off. The course was fun and I’ve been proud of everything i achieved during the course. My friends showed up to support me, and seeing people smile while playing my game was the best part. Zion and Fausto even set the highest score at 77! Here are some pictures and videos from the showcase.
rose playing –> My friend Rose Playing my game
Structure + Challenges
The structure of the project is crafted using recycled cardboard and cork that I found at home, a gesture to honor COP28 held in the UAE. Unfortunately, I couldn’t access the resources and equipment in the IM lab, as I wasn’t available during the weekend. Nevertheless, I am proud of how the prototype turned out. It has a homemade aesthetic that truly showcases the effort and creativity I invested in it. *Update: I drew road markings on the pink paper, to easily direct left right and middle*
The challenges I encountered primarily involved reacquainting myself with p5. After a break spent focusing on Arduino, I felt a bit out of touch with p5 and needed to catch up on some of its features. However, I am pleased with the final result, particularly the pink color scheme I chose, which I feel represents me well. Another significant challenge was working with Arduino. I frequently faced connectivity issues with my laptop, requiring multiple restarts whenever it failed to upload. Additionally, getting the ultrasonic sensor to accurately measure distances was tricky, but after consulting numerous videos, I managed to overcome this obstacle. Despite these challenges, I am proud of what I accomplished. *Update: the issue of the arduino lagging was fixed by Muhammad Khan who was kind enough to fix the code for me, now Id say it works perfectly with no lag*
let car, helloKitty; // images for car and Hello Kitty character let phase = "startScreen"; // current phase of the game: startScreen, game, endScreen, instructions let speedCount = 0; // counter to track speed and timing of game elements let speed = 1; // initial speed of moving cars let cars = []; // array to hold car objects for collision detection and rendering let gameOverImg; // image to be displayed when the game is over let arduinoData = 0; // data received from Arduino for control let useArduinoControl = true; // flag to enable or disable Arduino control let rVal = 0; // ------------------------------------------------------------------------------------- // preloads game assets (images, fonts, sounds) // before starting the game function preload() { car = loadImage("pink1.png"); helloKitty = loadImage("hellokitty.png"); StartUp = loadImage("workpls.png") customfontkitty = loadFont('kittyfont2.ttf'); customfontsan = loadFont('san.ttf'); gameOverSound = loadSound("ouch.mp3"); introSound = loadSound("introsong.mp3"); leftBorder = loadImage("leftBorder.png"); rightBorder = loadImage("rightBorder.png"); instructionImg = loadImage("instructions8.png"); } // ---------------------------------------------------------------------------- // sets up the initial state of the game canvas and variables function setup() { createCanvas(400, 600); rectMode(CENTER); imageMode(CENTER); kittyX = 115; // initial X position for Hello Kitty kittyY = 550; // initial Y position for Hello Kitty score = 0; // initialize score level = 1; // initialize game level } // ---------------------------------------------------------------------------- // The main game loop, executed continuously to render the game function draw() { background(50, 140, 80); // set the background color if (phase == "game") { fill(255,204,220); noStroke(); // fisplay the left and right border images on the screen image(leftBorder, 20,height/2,leftBorder.width*0.55,leftBorder.height*0.55); image(rightBorder, 380,height/2,rightBorder.width*0.55,rightBorder.height*0.55); // draw the central playing area rect(width / 2, height / 2, 320, height); fill(255); // creates the road markings for (let i = 0; i < 4; i++) { for (let j = -1; j < 10; j++) { rect(75 + i * 80, (speedCount % 60) + 30 + 60 * j, 6, 50); } } // increment speedCount to control the moving speed of road markings speedCount += speed; // arduino Control: Move Hello Kitty based on Arduino input if (useArduinoControl && arduinoData !== null) { if (arduinoData < 10) { // move left kittyX = 115; } else if (arduinoData >= 10 && arduinoData < 20) { // Move center kittyX = 195; } else if (arduinoData >= 20) { // Move right kittyX = 275; } } // returns the hello kitty to current position image(helloKitty, kittyX, kittyY, 70, 100); // on every 50th speed count a car will come down if (speedCount % 200 == 0) { cars.push({ x: random([115, 115 + 80, 115 + 160]), // Random lane y: -40, // Start above the screen }); } // move each car for (let i = 0; i < cars.length; i++) { image(car, cars[i].x, cars[i].y, 70, 100); // checks for collision with Hello Kitty if (dist(cars[i].x, cars[i].y, kittyX, kittyY) < 60) { phase = "gameOver"; gameOverImg = get(0, 0, width, height); gameOverSound.play(); introSound.stop(); } // update car position cars[i].y += speed * 2; } // display score and level textSize(16); stroke(255); strokeWeight(2); fill("#9B858D"); text("SCORE : " + score, 20, 30); text("LEVEL : " + level, 320, 30); // increment score over time if (frameCount % 60 == 0) { score++; } // increase speed and level after certain intervals if (speedCount % 1000 == 0) { speed += 1; level += 1; } } // ---------------------------------------------------------------------------- // display the game over screen and show score and level reached if (phase == "gameOver") { image(gameOverImg,width/2,height/2); textSize(16); strokeWeight(2); stroke(0); fill(0, 100); rect(width / 2, height / 2, 240, 150); fill(255); stroke(255); strokeWeight(1); text("Level " + level + " Reached", 145, 250); textSize(14); text(" You Scored " + score, 145, 360); text(" press Enter to Restart", 135, 330); fill(255); textSize(32); text(" GAME OVER", 105, 300); } // checks if the current game phase is the start screen if (phase == "startScreen") { if(!introSound.isPlaying()){ introSound.loop(); } // ---------------------------------------------------------------------------- // start up image and text background("#9B858D"); fill(255,192,203,0.60); image(StartUp, width/2, height/2, StartUp.width*0.7, StartUp.height*0.7); rect(width / 2, height / 2, 380, 580); stroke(255); fill(255); strokeWeight(6); stroke(255, 192, 230); fill(255, 105, 180); textFont(customfontkitty); textSize(86); text("hello kitty", 20, 120); fill(255, 105, 180) textSize(60); strokeWeight(2) stroke(255); textFont(customfontkitty); text("adventure", 70, 175); fill(171,209,158); rect(width / 2, 480, 200, 80, 50); fill(255); textFont(customfontkitty); text("start", 140, 500); stroke(171,209,158); strokeWeight(2) fill(255); textSize(28); text(" Press Enter for Instructions",10,570) // check if the mouse position is within a specified rectangular area if ( mouseX > width / 2 - 100 && mouseX < width / 2 + 100 && mouseY > 460 && mouseY < 540 ) { // If the mouse is within the specified area it changes to game phase if (mouseIsPressed) { mouseIsPressed = false; phase = "game"; } } } // ------------------------------------------------------------------------------------- // intruction page if (phase == "instruction"){ image(instructionImg,200,300,400,600); // display the instruction image strokeWeight(2); stroke(0); textSize(60); textFont(customfontkitty); fill(0); text("How To Play",40,120); textFont(); textFont(customfontsan); strokeWeight(1); textSize(20); text(" \n 1) move your hands left \n and right to move \n hello kitty \n 2) try to avoid the cars \n 3) BE SAFE!",60,330); textSize(20); text(" press enter to go back \n and start! ",70,500) } } // function to handle keyboard inputs function keyPressed() { // game control using arrow keys during the 'game' phase if (phase == "game") { switch (key) { case "ArrowLeft": if (kittyX > 115) { kittyX -= 80; } break; case "ArrowRight": if (kittyX < 260) { kittyX += 80; } break; default: break; } } // restart the game when 'Enter' is pressed in the 'gameOver' phase if (phase == "gameOver") { if (key == "Enter") { score = 0; level = 1; speedCount = 0; speed = 0; cars = []; phase = "startScreen"; kittyX = 75; kittyY = 550; key=""; } } // handle key presses for navigating between instruction and start screen if(phase=="instruction"){ if(key== "Enter"){ phase = "startScreen"; key=""; } } if(phase=="startScreen"){ if(key== "Enter"){ phase = "instruction"; key=""; } } // setup serial communication when spacebar is pressed if (key == " ") { setUpSerial(); } } // ------------------------------------------------------------------------------------- // arduino function mouseIsPressed() { readSerial(); } // This function will be called by the web-serial library // with each new line of data. The serial library reads // the data until the newline and then gives it to us through // this callback function let lastDataReceivedTime = 0; function readSerial(data) { if (data != null) { arduinoData = parseInt(data); lastDataReceivedTime = millis(); useArduinoControl = true; } else if (millis() - lastDataReceivedTime > 2000) { // 2 seconds timeout useArduinoControl = false; } let sendToArduino = 0; switch (phase) { case 'game': sendToArduino = 1; break; case 'instruction': case 'startScreen': sendToArduino = 2; break; case 'gameOver': sendToArduino = 3; break; } writeSerial(sendToArduino + "\n"); }
const int trigPin = 9; // Pin number for the ultrasonic sensor's trigger pin const int echoPin = 10; // Pin number for the ultrasonic sensor's echo pin const int ledgreen = 4; // Pin number for the green LED const int ledred = 7; // Pin number for the red LED long duration; // Variable to store the duration of the echo pulse float distance; // Variable to store the calculated distance void setup() { pinMode(trigPin, OUTPUT); // Set the trigPin as an output pinMode(echoPin, INPUT); // Set the echoPin as an input Serial.begin(9600); // Start serial communication at 9600 pinMode(ledgreen, OUTPUT); // Set the green LED pin as an output pinMode(ledred, OUTPUT); // Set the red LED pin as an output } unsigned long ultrasonic_clock = 0; unsigned long led_clock = 0; float sum = 0; int iterator = 0; void loop() { if (millis() - ultrasonic_clock >= 5) // Take reading every 5 ms { ultrasonic_clock = millis(); digitalWrite(trigPin, LOW); // Clear the trigPin delayMicroseconds(2); digitalWrite(trigPin, HIGH); // Set the trigPin to HIGH state for 10 microseconds delayMicroseconds(10); digitalWrite(trigPin, LOW); // Set the trigPin to LOW state duration = pulseIn(echoPin, HIGH); // Read the echoPin, returns the sound wave travel time in microseconds distance = duration * 0.034 / 2; // Calculate the distance sum += distance; iterator++; if (iterator == 5) // Average the last 5 readings { Serial.println(int(sum / 5)); iterator = 0; sum = 0; } } if (millis() - led_clock >= 10) // Take reading every 10 ms { led_clock = millis(); //record the time this code ran // reading brightness level from serial // int brightness = Serial.parseInt(); if(Serial.read() == '\n'){ // controlling LED based on brightness level if(brightness == 1){ digitalWrite(ledgreen, HIGH); digitalWrite(ledred, LOW); } else if(brightness == 2){ digitalWrite(ledgreen, LOW); digitalWrite(ledred, LOW); } else if(brightness == 3){ digitalWrite(ledred, HIGH); digitalWrite(ledgreen, LOW); } } } }
Improvements
For future improvements, I aim to rely less on external help, as I did encounter significant struggles. I plan to apply the skills acquired from tool training to craft an even better prototype using materials like wood and acrylic. Additionally, I’ll consider utilizing various components to enhance the game or possibly explore a different direction and different sensors for this project. Starting earlier will also be a priority, allowing ample time for revisions, enhancements, and potentially incorporating more features. Overall, I am proud of my work and have gained a deep appreciation for the effort, thought, and creativity required by those who do this professionally. Creating a project that not only reflects my aesthetic but also functions effectively has been a rewarding experience. I am extremely pleased with the outcome and feel a sense of accomplishment for what I have achieved.
Sources –
Song : https://www.youtube.com/watch?v=DTU2VpTJ0So
Ouch : https://www.youtube.com/watch?v=J6l4TVqTRpU
Hello Kitty : https://www.pinterest.com/pin/500884789807456421/
Instruction Background : https://www.pinterest.com/pin/2111131070738280/
Instruction Frame : https://www.pinterest.com/pin/4292562138085566/
Help –
https://www.youtube.com/watch?v=0Lhgd8PQmn0
https://www.youtube.com/watch?v=6F1B_N6LuKw
https://editor.p5js.org/azimovbob/sketches/LkvG5pT5g
https://editor.p5js.org/kellycarvalho2024/sketches/tDFpv6VLi
https://github.com/mzohaibnaz/CarRacing-p5
https://medium.com/@yyyyyyyuan/tutorial-serial-communication-with-arduino-and-p5-js-cd39b3ac10ce
https://www.youtube.com/watch?v=feL_-clJQMs
https://labor.99grad.de/typo3-docs/nnarduino/sensors/80_utrasonic/index.html