FINAL PROJECT- FEED FLYNN

Final Project Introduction:

LADIES AND GENTELMEN!!!! I DID ITTTTTT:

  • Describe your concept

I aimed to delve into recreating a retro game named “Feed Flynn,” blending the Catcher and spaceship Tyrian games into one fun experience. Inspired by the saying “don’t eat the book” and my deep fondness for food, I wanted to craft a game celebrating my love for food—an arcade-style creation I call “Feed Flynn.”

You get points for Feeding Flynn donuts +10,

Burgers ( full Meal ) + 20

Books -3 (why would you even feed Flynn Books ;( )

Flynn also has the ability to shoot bullets to eliminate the books. It’s a 35-second challenge to compete for the highest score, a way to test your skills and challenge your friends for the top spot!

The game adopts a retro vibe with:

  • A glitchy character sprite
  • Pixelated character design
  • Incorporation of music and sound effects
  • Include some pictures / video of your project interaction

this is how my project hardware is looking ( retro arcade)

I decided to have my single line of instruction Do NOT eat the books on the box; Condensing complex rules into concise, clear instructions often enhances comprehension and user engagement

  • How does the implementation work?
    • Description of interaction design

Interaction design involves creating the interface between a user and a system, aiming to optimize the user’s experience. In the context of “Feed Flynn,” the game utilizes four arcade buttons to facilitate the player’s interaction:

      • Start/Restart Button: This button initiates the game or restarts it once it’s over. It serves as the gateway to engage with the game, allowing the player to enter the gaming experience.
      • Right/Left Buttons: These two buttons enable the movement of Flynn, the character, within the game. They provide directional control, allowing Flynn to navigate right or left within the gaming environment, dodging falling objects or positioning to catch desired items.
      • Bullet Firing Button: This button empowers Flynn to shoot bullets in the game. By pressing this button, players can eliminate books, preventing them from being consumed by Flynn and avoiding point deductions. It adds an element of strategy and skill to the gameplay, requiring players to decide when to fire bullets strategically.
      • Description of Arduino code and include or link to full Arduino sketch
    • const int buttonStartPin = 2;   // Pin for the start button
      const int buttonLeftPin = 3;    // Pin for the left button
      const int buttonRightPin = 4;   // Pin for the right button
      const int buttonFirePin = 5;    // Pin for the fire button
      
      void setup() {
        Serial.begin(9600);
        pinMode(buttonStartPin, INPUT_PULLUP);
        pinMode(buttonLeftPin, INPUT_PULLUP);
        pinMode(buttonRightPin, INPUT_PULLUP);
        pinMode(buttonFirePin, INPUT_PULLUP);
      }
      
      void loop() {
        int startButtonState = digitalRead(buttonStartPin);
        int leftButtonState = digitalRead(buttonLeftPin);
        int rightButtonState = digitalRead(buttonRightPin);
        int fireButtonState = digitalRead(buttonFirePin);
      
        // Invert button states before sending to serial
        Serial.print(!startButtonState);
        Serial.print(",");
        Serial.print(!leftButtonState);
        Serial.print(",");
        Serial.print(!rightButtonState);
        Serial.print(",");
        Serial.println(!fireButtonState);
        
        delay(100); // Optional delay to stabilize readings
      }
      

       

      • Description of p5.js code and embed p5.js sketch in post
  • let catcherX, catcherY; // Declaring variables for catcher position
    let objects = []; // Array to store falling objects
    let objectSpeed; // Variable to control object speed
    let gameStarted; // Flag to track game state
    let serial; // Serial port communication variable
    let points; // Variable to track player points
    let startTime; // Start time of the game
    let gameDuration; // Duration of the game
    let fireButtonState = 0; // State of the fire button
    let bullets = []; // Array to store bullets
    let backgroundImage; // Variable to hold a background image
    let backgroundImage2; // Another background image variable
    let backgroundImage3; // Third background image variable
    let catcherFrames = []; // Array to store frames of the sprite sheet
    let catcherIndex = 0; // Index to track the current frame
    let catcherSpeed = 0.2; // Speed of the catcher animation
    var gif; // Variable for a GIF element
    let catchSound; // Sound variable for catching objects
    
    
    function preload() {   // Loading assets
    
      
      backgroundImage = createImg("https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExOHlzcmp4MTh1bDJqMTMzbXAyOTAzMHgxcTk0bmUyYXJncXBpd2d4cSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/LV4MGiLrYrNaF3Dpbn/giphy.gif");
      backgroundImage2 = loadImage("2.png");
      backgroundImage3 = loadImage("6.png");
      bungeeFont = loadFont('Bungee-Regular.ttf');
      catcherSheet = loadImage('8.png');
      books = loadImage("3.png");
      donut = loadImage("4.png");
      burger = loadImage("5.png");
      gif = createImg("https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNHBldTFuczNob251M3NiNjJ6cGl1aHczM3ZoN2c1em9hdXB5YTJvdSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9cw/96t0nzIf5cgGrCdxFZ/giphy.gif");
      gif.hide();
      
        gameStartSound = loadSound('07. STAGE 2 [PC Engine]-1.mp3');
      gameOverSound = loadSound('33. GAME OVER [PC-9801]-1.mp3');
      
      catchSound = loadSound('heavy_swallowwav-14682.mp3');
    
    }
    
    
    
    
     // Setup canvas and initial game conditions
    function setup() {
      createCanvas(889, 500);
      catcherX = width / 2;
      catcherY = height - 50;
      objectSpeed = 2;
      gameStarted = 0;
      points = 0;
      gameDuration = 35; 
      startTime = millis();
    
      serial = new p5.SerialPort();
      serial.open('COM6'); 
      serial.on('data', serialEvent);
    }
    
    // Game loop managing different game states
    function draw() {
      
      if (gameStarted === 0 ) {
    
        // Display the appropriate background image 
        
        backgroundImage.size(889,500);
        
            if (!gameStartSound.isPlaying()) {
          gameStartSound.play();
        }
    
      } else if (gameStarted === 1) {
        
        backgroundImage.hide();
        image(backgroundImage2, 0, 0, width, height);
       gif.show();
      gif.position(catcherX - 100, catcherY - 60);
      gif.size(200,100)
        // Draw catcher and game elements
        drawGame();
      }
    }
    
    // Function handling the core game logic and rendering
    function drawGame() {
      let currentTime = millis();
      let elapsedTime = (currentTime - startTime) / 1000; // Elapsed time in seconds
      let remainingTime = gameDuration - floor(elapsedTime); // Remaining time in seconds
      
      
      textSize(16);
      fill(0);
      textAlign(RIGHT);
      text(`Time: ${remainingTime}`, width - 80, 52);
      
      fill("rgba(0,255,0,0)");
      noStroke();
      // Draw catcher
      ellipseMode(CENTER); // Set ellipse mode to CENTER
      catcherX = constrain(catcherX, 25, width - 25);
      ellipse(catcherX, catcherY, 50, 50); // Draw a circle for the catcher
      
    
    
      // Generate falling objects continuously
      if (frameCount % 30 === 0) {
        objects.push(...generateObjects(3));
      }
    
      // Draw falling objects
      for (let obj of objects) {
        drawObject(obj);
    
        obj.y += objectSpeed;
    
        // Check for catch
        if (
          obj.y > catcherY - 10 &&
          obj.y < catcherY + 10 &&
          obj.x > catcherX - 25 &&
          obj.x < catcherX + 25
        ) {
          handleCatch(obj);
        }
      }
    
        fill(0);
      // Display points
      textSize(16);
      text(`Points: ${points}`, 170 , 50);
      textFont(bungeeFont);
      
      
      // Handle bullets
      handleBullets();
    
      // Check for game over
      if (millis() - startTime >= gameDuration * 1000) {
        displayGameOver();
      }
    }
    
    // Handling keyboard input for catcher movement
    function keyPressed() {
      const catcherSpeed = 5;
      if (keyCode === LEFT_ARROW) {
        catcherX -= catcherSpeed;
      } else if (keyCode === RIGHT_ARROW) {
        catcherX += catcherSpeed;
      }
    }
    
    // Handling serial port events for game control
    function serialEvent() {
      let data = serial.readLine();
      if (data !== null) {
        let states = data.split(',');
        let startButtonState = parseInt(states[0]);
        let leftButtonState = parseInt(states[1]);
        let rightButtonState = parseInt(states[2]);
        fireButtonState = parseInt(states[3]);
    
        const catcherSpeed = 10;
        if (startButtonState === 1) {
          if (gameStarted !== 1) {
            gameStarted = 1;
            points = 0; // Reset points to zero when the game starts
            startTime = millis();
          }
        }
    
        if (gameStarted) {
          if (leftButtonState === 1) {
            catcherX -= catcherSpeed;
          } else if (rightButtonState === 1) {
            catcherX += catcherSpeed;
          }
        }
      }
    }
    
    // Generating falling objects
    function generateObjects(numObjects) {
      let generatedObjects = [];
      for (let i = 0; i < numObjects; i++) {
        let type;
        let rand = random();
        if (rand < 0.2) {
          type = 'square';
        } else if (rand < 0.6) {
          type = 'circle';
        } else {
          type = 'triangle';
        }
        let obj = {
          x: random(width),
          y: random(-50, -10),
          type: type,
        };
        generatedObjects.push(obj);
      }
      return generatedObjects;
    }
    
    // Drawing and displaying falling objects
    function drawObject(obj) {
      fill("rgba(0,255,0,0)");
      noStroke();
      
      if (obj.type === 'triangle') {
        ellipse(obj.x, obj.y, 30, 30); 
        image(books, obj.x - 45, obj.y - 35, 90, 55); 
      } else if (obj.type === 'circle') {
        ellipse(obj.x, obj.y, 30, 30); 
        image(donut, obj.x - 39, obj.y - 22.5, 80, 45); 
      } else if (obj.type === 'square') {
        ellipse(obj.x - 10, obj.y - 10, 30, 30); 
        image(burger, obj.x - 60, obj.y - 45, 100, 60); 
      }}
    
    // Handling catcher interaction with falling objects
    function handleCatch(obj) {
      if (obj.type === 'triangle') {
        points -= 3;
      } else if (obj.type === 'circle') {
        points += 10;
      } else if (obj.type === 'square') {
        points += 20;
      }
    catchSound.play(); // Play the sound when the catcher catches an object
      objects.splice(objects.indexOf(obj), 1);
    }
    
    
      // Handling bullet mechanics
    function handleBullets() {
      if (fireButtonState === 1) {
        bullets.push({ x: catcherX, y: catcherY });
      }
    
      for (let i = bullets.length - 1; i >= 0; i--) {
        let bullet = bullets[i];
        bullet.y -= 5;
        fill(255, 0, 0);
        ellipse(bullet.x, bullet.y, 5, 10);
    
        for (let j = objects.length - 1; j >= 0; j--) {
          let obj = objects[j];
          if (dist(bullet.x, bullet.y, obj.x, obj.y) < 15 && obj.type === 'triangle') {
            objects.splice(j, 1);
            bullets.splice(i, 1);
            points += 5;
          }
        }
    
        if (bullet.y < 0) {
          bullets.splice(i, 1);
        }
      }
    }
    
      // Displaying the game over screen
    function displayGameOver() {
      
      gameStartSound.stop();
      
      gameOverSound.play();
        fill(0);
      // Display game over screen
      textFont(bungeeFont);
      image(backgroundImage3, 0, 0, width, height);
      console.log("Game Over");
      textAlign(CENTER);
      textSize(24);
      fill(0);
      text("Game Over", width / 2, height / 2 - 90) ;
      text(`Your Score: ${points}`, width / 2, height / 2 );
      gameStarted = 2;
      gif.hide();
    }
    • Describtion of the code:
    • Variables: Various variables are declared to manage game elements such as catcher position, falling objects, game state, time, sound, and image assets.
    • preload(): Preloading assets like images, sounds, and fonts before the game starts.
    • setup(): Initializing the canvas size, setting initial game conditions like catcher position, object speed, and game duration, as well as initializing the serial port communication.
    • draw(): The main game loop that manages different game states and calls specific functions based on the game state.
    • drawGame(): Handles the core game logic and rendering. Manages time, displays game elements, generates falling objects, checks for collisions, and handles points and game over conditions.
    • keyPressed(): Listens for keypress events to control the catcher’s movement.
    • serialEvent(): Handles events from the serial port for game control (button presses, etc.).
    • generateObjects(): Generates falling objects of different types (triangle, circle, square).
    • drawObject(): Draws and displays the falling objects based on their types (triangle, circle, square) using images.
    • handleCatch(): Manages the interaction between the catcher and falling objects, updating points and removing caught objects.
    • handleBullets(): Handles the bullet mechanics, allowing the catcher to shoot at falling objects, awarding points upon successful hits.
    • displayGameOver(): Displays the game over screen, stops game sounds, shows the final score, and resets game states.
      • Description of communication between Arduino and p5.js

At first, I struggled a lot with understanding serial communication. It was hard, and it made it tough to communicate well for the project. But when I asked for help and used the p5 .exe desktop app better, things got easier. Learning how to use it properly helped me improve how I communicated for the project.

  • What are some aspects of the project that you’re particularly proud of?

I’m really happy with the graphics! Being a graphic designer, I put a lot of effort into creating Flynn and the game design. It was super fun to work on this video game, and I don’t think it’ll be my last! This time around, I loved playing with pixels, making animations, and exploring different pixel art styles for that cool retro theme.

I also noticed a visual connection between my Midterm Game “CatsAway” and this project. Both have this joyful vibe and a surreal feel, especially flying around and munching on books, which is part of my art style.

  • What are some areas for future improvement?

Accessibility: I’m aiming to ensure the game is accessible to a wider audience by making it compatible across different devices or platforms. This improvement will make the game available to more players, which is a goal I’m focused on.

 

Leave a Reply