Phaser, Fast Foodie Project, Finally Complete!

So I finally did it. After weeks of combing through code and having to redo some areas, I finally got the project to work. Okay, cards on the table, I’m not that good with coding or programming. In fact, most of my work here was done with the help of the AI Assistant and looking at other people’s code to see how it works. And even after that was still a challenge for me to piece everything together in a way that makes all the code work right.

This was an incredibly difficult project to work on, and I believe that I completed it to the best of my abilities. And now I believe I have a better understanding of how coding works in game development.

So, if anyone wants to comment or leave any suggestions on how I can improve my code, go ahead and do so. Any amount helps.

const gameState = {
score: 0,
starRating: 5,
currentWaveCount: 1,
customerIsReady: false,
cam: {},
gameSpeed: 3,
currentMusic: {},
totalWaveCount: 3,
readyForNextOrder: true,
customersServedCount: 0,
timeToServe: 5000
};

// Gameplay scene
class GameScene extends Phaser.Scene {
constructor() {
super({ key: “GameScene” });
}

preload() {
  // Preload images
  const baseURL = "https://content.codecademy.com/courses/learn-phaser/fastfoodie/";
  this.load.image("Chef", `${baseURL}art/Chef.png`);
  this.load.image("Customer-1", `${baseURL}art/Customer-1.png`);
  this.load.image("Customer-2", `${baseURL}art/Customer-2.png`);
  this.load.image("Customer-3", `${baseURL}art/Customer-3.png`);
  this.load.image("Customer-4", `${baseURL}art/Customer-4.png`);
  this.load.image("Customer-5", `${baseURL}art/Customer-5.png`);
  this.load.image("Floor-Server", `${baseURL}art/Floor-Server.png`);
  this.load.image("Floor-Customer", `${baseURL}art/Floor-Customer.png`);
  this.load.image("Tray", `${baseURL}art/Tray.png`);
  this.load.image("Barrier", `${baseURL}art/Barrier.png`);
  this.load.image("Star-full", `${baseURL}art/Star-full.png`);
  this.load.image("Star-half", `${baseURL}art/Star-half.png`);
  this.load.image("Star-empty", `${baseURL}art/Star-empty.png`);

  // Preload song
  this.load.audio("gameplayTheme", [
    `${baseURL}audio/music/2-gameplayTheme.ogg`,
    `${baseURL}audio/music/2-gameplayTheme.mp3`,
  ]); // Credit: "Pixel Song #18" by hmmm101: https://freesound.org/people/hmmm101

  // Preload SFX
  this.load.audio("placeFoodSFX", [
    `${baseURL}audio/sfx/placeFood.ogg`,
    `${baseURL}audio/sfx/placeFood.mp3`,
  ]); // Credit: "action_02.wav" by dermotte: https://freesound.org/people/dermotte

  this.load.audio("servingCorrectSFX", [
    `${baseURL}audio/sfx/servingCorrect.ogg`,
    `${baseURL}audio/sfx/servingCorrect.mp3`,
  ]); // Credit: "Video Game SFX Positive Action Long Tail" by rhodesmas: https://freesound.org/people/djlprojects

  this.load.audio("servingIncorrectSFX", [
    `${baseURL}audio/sfx/servingIncorrect.ogg`,
    `${baseURL}audio/sfx/servingIncorrect.mp3`,
  ]); // Credit: "Incorrect 01" by rhodesmas: https://freesound.org/people/rhodesmas

  this.load.audio("servingEmptySFX", [
    `${baseURL}audio/sfx/servingEmpty.ogg`,
    `${baseURL}audio/sfx/servingEmpty.mp3`,
  ]); // Credit: "Computer Error Noise [variants of KevinVG207's Freesound#331912].wav" by Timbre: https://freesound.org/people/Timbre

  this.load.audio("fiveStarsSFX", [
    `${baseURL}audio/sfx/fiveStars.ogg`,
    `${baseURL}audio/sfx/fiveStars.mp3`,
  ]); // Credit: "Success 01" by rhodesmas: https://freesound.org/people/rhodesmas

  this.load.audio("nextWaveSFX", [
    `${baseURL}audio/sfx/nextWave.ogg`,
    `${baseURL}audio/sfx/nextWave.mp3`,
  ]); // Credit: "old fashion radio jingle 2.wav" by rhodesmas: https://freesound.org/people/chimerical
}

create() {
  
  // Stop, reassign, and play the new music
  gameState.currentMusic.stop();
  gameState.currentMusic = this.sound.add("gameplayTheme");
  gameState.currentMusic.play({ loop: true });

  // Assign SFX
  gameState.sfx = {};
  gameState.sfx.placeFood = this.sound.add("placeFoodSFX");
  gameState.sfx.servingCorrect = this.sound.add("servingCorrectSFX");
  gameState.sfx.servingIncorrect = this.sound.add("servingIncorrectSFX");
  gameState.sfx.servingEmpty = this.sound.add("servingEmptySFX");
  gameState.sfx.fiveStars = this.sound.add("fiveStarsSFX");
  gameState.sfx.nextWave = this.sound.add("nextWaveSFX");

  // Create environment sprites
  gameState.floorServer = this.add.sprite(gameState.cam.midPoint.x, 0, "Floor-Server").setScale(0.5).setOrigin(0.5, 0);
  gameState.floorCustomer = this.add.sprite(gameState.cam.midPoint.x, gameState.cam.worldView.bottom,"Floor-Customer").setScale(0.5).setOrigin(0.5, 1);
  gameState.table = this.add.sprite(gameState.cam.midPoint.x, gameState.cam.midPoint.y, "Barrier").setScale(0.5);

  // Create player and tray sprites
  gameState.tray = this.add.sprite(gameState.cam.midPoint.x, gameState.cam.midPoint.y, "Tray").setScale(0.5);
  gameState.player = this.add.sprite(gameState.cam.midPoint.x, 200, "Chef").setScale(0.5);

  // Display the score
  gameState.scoreTitleText = this.add.text(gameState.cam.midPoint.x, 30, "Score", { fontSize: "15px", fill: "#666666" }).setOrigin(0.5);
  gameState.scoreText = this.add.text(gameState.cam.midPoint.x, gameState.scoreTitleText.y + gameState.scoreTitleText.height + 20, gameState.score, { fontSize: "30px", fill: "#000000" }).setOrigin(0.5);

  // Display the wave count
  gameState.waveTitleText = this.add.text(gameState.cam.worldView.right - 20, 30, "Wave", { fontSize: "64px", fill: "#666666" }).setOrigin(1, 1).setScale(0.25);
  gameState.waveCountText = this.add.text(gameState.cam.worldView.right - 20, 30, gameState.currentWaveCount + "/" + gameState.totalWaveCount, { fontSize: "120px", fill: "#000000" }).setOrigin(1, 0).setScale(0.25);

  // Display number of customers left
  gameState.customerCountText = this.add.text(gameState.cam.worldView.right - 20, 80, `Customers left: ${gameState.customersLeftCount}`, { fontSize: "15px", fill: "#000000" }).setOrigin(1);

  // Generate wave group
  gameState.customers = this.add.group();
  this.generateWave();

  gameState.currentMeal = this.add.group()
  gameState.currentMeal.fullnessValue = 0

  gameState.keys.Enter = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.ENTER);
  gameState.keys.A = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
  gameState.keys.S = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
  gameState.keys.D = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);

  // Create Stars
  gameState.starGroup = this.add.group();
  this.drawStars();

  // Create Timer
  gameState.timer = this.time.addEvent({
    delay: gameState.timeToServe,
    loop: false,
    paused: true
  })
}

update() {
  if (gameState.readyForNextOrder === true) {
    gameState.readyForNextOrder = false
    gameState.customerIsReady = false
    
    for (let iii = 0; iii < gameState.customersServedCount; iii++){
      let previousCustomer = this.tweens.add({
        targets: gameState.customers.children.entries[iii],
        duration: 750,
        x:  '-=300',
        angle: 0,
      });
      gameState.customers.children.entries[iii].meterContainer.visible = false
    }
    
    gameState.currentCustomer = gameState.customers.children.entries[gameState.customersServedCount];
    /*
    console.log('Current Customer:', gameState.currentCustomer);
    */
    if (gameState.readyForNextOrder && !gameState.customerIsReady) {
      gameState.readyForNextOrder = false;
      gameState.customerIsReady = false;
    }
      let tween = this.tweens.add({
        targets: gameState.currentCustomer,
        duration: 1000,
        delay: 100,
        angle: 90,
        x: gameState.player.x,
        ease: 'Power2',
        onComplete: function() {
          /*
          console.log('Tween Complete for Customer:', gameState.currentCustomer);
          */
          gameState.customerIsReady = true;
          gameState.currentCustomer.meterContainer.visible = true;
          gameState.timer.paused = false;
        }
      });
      
  
      for (let iv = gameState.customersServedCount + 1; iv < gameState.customers.children.entries.length; iv++) {
        gameState.nextCustomer = gameState.customers.children.entries[iv];
        let nextCustomer = this.tweens.add({
          targets: gameState.nextCustomer,
          delay: 200,
          x: '-=200',
          duration: 1500
        });
      }
    
  }
    
  if (Phaser.Input.Keyboard.JustDown(gameState.keys.A)) {
    this.placeFood('Burger', 5)
    } else if (Phaser.Input.Keyboard.JustDown(gameState.keys.S)) {
    this.placeFood('Fries', 3)
    } else if (Phaser.Input.Keyboard.JustDown(gameState.keys.D)) {
    this.placeFood('Shake', 1)
    } else if (Phaser.Input.Keyboard.JustDown(gameState.keys.Enter)){
      if (gameState.readyForNextOrder === false && gameState.customerIsReady === true){
        this.moveCustomerLine();
        this.updateCustomerCountText();
        gameState.timer.paused = true;
        gameState.timer.remove();
        gameState.timer = this.time.addEvent(gameState.timer)
      }
    }
    
    if (gameState.timer.paused === false){
      let timePassed = gameState.timer.getProgress()
      gameState.currentCustomer.timerMeterBody.width = gameState.currentCustomer.meterBase.width - (gameState.currentCustomer.meterBase.width * timePassed)
      if (timePassed > 0.25 && timePassed < 0.75){
        gameState.currentCustomer.timerMeterBody.setFillStyle(0xFF9d00)
      }else if (timePassed > 0.75){
        gameState.currentCustomer.timerMeterBody.setFillStyle(0xDB533A) 
      }
        if (timePassed === 1){
          this.moveCustomerLine();
          this.updateCustomerCountText();
          gameState.timer.paused = true;
          gameState.timer.remove();
          gameState.timer = this.time.addEvent(gameState.timer)
        } 
    }

    if (gameState.starRating <= 0){
      gameState.currentMusic.stop();
      this.scene.stop('GameScene');
      this.scene.start('LoseScene');
      this.restartGame();
    }

    if (gameState.currentWaveCount > 3){
      gameState.currentMusic.stop();
      this.scene.stop('GameScene');
      this.scene.start('WinScene');
      this.restartGame();
    } 
  
}

updateCustomerCountText(){
  gameState.customersLeftCount = gameState.totalCustomerCount - gameState.customersServedCount 
  gameState.customerCountText.setText(`Customers left: ${gameState.customersLeftCount}`)
}
/* WAVES */
// Generate wave
generateWave() {
  // Add the total number of customers per wave here:
  
  gameState.totalCustomerCount = Math.ceil(Math.random() * 10) * gameState.currentWaveCount;

  this.updateCustomerCountText();

  for (let i = 0; i < gameState.totalCustomerCount; i++) {
    // Create your container below and add your customers to it below:
    let customerContainer = this.add.container(gameState.cam.worldView.right + (200 * i), gameState.cam.worldView.bottom - 140);

    gameState.customers.add(customerContainer);

    // Customer sprite randomizer
    let customerImageKey = Math.ceil(Math.random() * 5);

    // Draw customers here!
    let customer = this.add.sprite(0, 0, `Customer-${customerImageKey}`).setScale(0.5);
    customerContainer.add(customer);

    // Fullness meter container
    customerContainer.fullnessMeter = this.add.group();

    // Define capacity
    customerContainer.fullnessCapacity = Math.ceil(Math.random() * 5 * gameState.totalWaveCount);

    // If capacity is an impossible number, reshuffle it until it isn't
    while (customerContainer.fullnessCapacity === 12 ||customerContainer.fullnessCapacity === 14) {
      customerContainer.fullnessCapacity = Math.ceil(Math.random() * 5) * gameState.totalWaveCount;
    }

    // Edit the meterWidth
    let meterWidth = customerContainer.fullnessCapacity * 10;
    
    customerContainer.meterContainer = this.add.container(0, customer.y + (meterWidth / 2));

    // Add the customerContainer.meterContainer to customerContainer
    customerContainer.add(customerContainer.meterContainer);

    // Add meter base
    customerContainer.meterBase = this.add.rectangle(-130, customer.y, meterWidth, 33, 0x707070).setOrigin(0);
    customerContainer.meterBase.setStrokeStyle(6, 0x707070);
    customerContainer.meterBase.angle = -90;
    customerContainer.meterContainer.add(customerContainer.meterBase);

    // Add timer countdown meter body
    customerContainer.timerMeterBody = this.add.rectangle(customerContainer.meterBase.x + 22, customer.y + 1, meterWidth + 4, 12, 0x3adb40).setOrigin(0);
    customerContainer.timerMeterBody.angle = -90;
    customerContainer.meterContainer.add(customerContainer.timerMeterBody);

    // Create container for individual fullness blocks
    customerContainer.fullnessMeterBlocks = [];

    // Create fullness meter blocks
    for (let j = 0; j < customerContainer.fullnessCapacity; j++) {
      customerContainer.fullnessMeterBlocks[j] = this.add.rectangle(customerContainer.meterBase.x, customer.y - (10 * j), 10, 20,0xdbd53a).setOrigin(0);
      customerContainer.fullnessMeterBlocks[j].setStrokeStyle(2, 0xb9b42e);
      customerContainer.fullnessMeterBlocks[j].angle = -90;
      customerContainer.fullnessMeter.add(customerContainer.fullnessMeterBlocks[j]);
      customerContainer.meterContainer.add(customerContainer.fullnessMeterBlocks[j]);
    }

    // Hide meters
    customerContainer.meterContainer.visible = false;
  }
}

placeFood(food, fullnessValue){

  if (gameState.currentMeal.children.entries.length < 3 && gameState.customerIsReady === true){
    let xPosition = gameState.tray.x-90
    switch (gameState.currentMeal.children.entries.length){
      case 1:
        xPosition += 90;
        break;
      case 2:
        xPosition += 180;
        break;
    }

    gameState.currentMeal.create(xPosition, gameState.tray.y, food).setScale(0.5)

  

  gameState.currentMeal.fullnessValue+=fullnessValue;
    for (let ii = 0; ii < gameState.currentMeal.fullnessValue; ii++){
      if (ii < gameState.currentCustomer.fullnessCapacity){
        if (gameState.currentMeal.fullnessValue === gameState.currentCustomer.fullnessCapacity){
          gameState.currentCustomer.fullnessMeterBlocks[ii].setFillStyle(0x3ADB40);
          gameState.currentCustomer.fullnessMeterBlocks[ii].setStrokeStyle(2, 0x2EB94E);
        } else if (gameState.currentMeal.fullnessValue > gameState.currentCustomer.fullnessCapacity){
          gameState.currentCustomer.fullnessMeterBlocks[ii].setFillStyle(0xDB533A);
          gameState.currentCustomer.fullnessMeterBlocks[ii].setStrokeStyle(2, 0xB92E2E);
      } else {gameState.currentCustomer.fullnessMeterBlocks[ii].setFillStyle(0xFFFA81);
      }
      gameState.sfx.placeFood.play();
      }
    }

  }

}

moveCustomerLine() {
  this.updateStars(gameState.currentMeal.fullnessValue, gameState.currentCustomer.fullnessCapacity);
  gameState.currentMeal.clear(true);
  gameState.currentMeal.fullnessValue = 0;
  gameState.customersServedCount += 1;
  /*
  console.log('Customers Served Count:', gameState.customersServedCount);
  */
  gameState.readyForNextOrder = true;
  if (gameState.customersServedCount === gameState.totalCustomerCount){
    gameState.currentWaveCount += 1;
    gameState.gameSpeed -= 1;
    gameState.readyForNextOrder = false;
    this.destroyWave();

  }
}

drawStars() {
  gameState.starGroup.clear(true, true);
  for (let i = 0; i < gameState.starRating; i++) {
    let starX = 20 + i * 50; // 20px offset and 50px space between stars
    let starY = 20; // 20px from the top
    gameState.starGroup.create(starX, starY, 'Star-full').setScale(0.5);
  }
}

updateStars(fullnessValue, fullnessCapacity) {
  if (fullnessValue === fullnessCapacity) {
    console.log(gameState.currentCustomer.fullnessValue);
    gameState.currentCustomer.list[0].setTint(0x3ADB40);
    gameState.sfx.servingCorrect.play();
    gameState.score += 100;
    gameState.scoreText.setText(`Score: ${gameState.score}`);
    if (gameState.starRating < 5) {
      gameState.starRating += 1;
      this.drawStars();
      if (gameState.starRating === 5) {
        gameState.sfx.fiveStars.play();
      }
    }
  } 
  if (fullnessValue < fullnessCapacity) {
    gameState.currentCustomer.list[0].setTint(0xDB533A);
    gameState.sfx.servingIncorrect.play();
    gameState.starRating = Math.max(0, gameState.starRating - 2);
    this.drawStars();
  } 
  if (fullnessValue > fullnessCapacity) {
    gameState.currentCustomer.list[0].setTint(0xDB9B3A);
    gameState.sfx.servingEmpty.play();
    gameState.starRating = Math.max(0, gameState.starRating - 1);
    this.drawStars();
  }
}

destroyWave() {
  // Play the next wave sound effect
  gameState.sfx.nextWave.play();
  for (let vi = 0; vi < gameState.customers.children.entries.length; vi++){
    let customer = gameState.customers.children.entries[vi];
    // Tween to move customers left and reset angles
    let tween = this.tweens.add({
      targets: customer,
      x: '-=300',
      angle: 0,
      duration: 500,
      onComplete: () => {
        // Tween to move customers off the screen
        this.tweens.add({
          targets: customer,
          x: '-=1000',
          duration: 500,
        })
      }
    })
  } 
  gameState.customersServedCount = 0;

  // Destroy old wave
  gameState.customers.clear(true, true);

  // Generate new wave
  this.generateWave();

  // Set ready for next order
  gameState.readyForNextOrder = true;

  // Update wave count display
  gameState.waveCountText.setText(`${gameState.currentWaveCount}/${gameState.totalWaveCount}`);
 
}

restartGame(){
  gameState.score = 0;
  gameState.starRating = 5;
  gameState.currentWaveCount = 1;
  gameState.customerIsReady = false;
  gameState.gameSpeed = 3;
  gameState.totalWaveCount = 3;
  gameState.readyForNextOrder = true;
  gameState.customersServedCount = 0;
  gameState.timeToServe = 5000;
}

}

Editor’s Note:

Something went wrong with uploading this to post, so this was the best I could do. let me know if you have any problems reading it.