# FastFoodie step 29

Hello,

I’m currently going through the final project in the Phaser.js, and I’m stuck on step 26 - 29 (placeFood method)

I got to step 29 which I cannot get past in my head… Below you can see steps 26 to 28 completed-ish… and need some help completing step 29…

Players will want visual feedback to know if they’ve served enough food. We can color the customer’s fullness capacity bars in different colors based on how filling the meal is.

Set the scaffolding for this by iterating through each of `gameState.currentMeal.fullnessValue` . Inside the loop add a check to see if the counter used in the iteration is less than `gameState.currentCustomer.fullnessCapacity` .

``````placeFood(food, fullnessValue) {
if (gameState.currentMeal.children.entries.length < 3 && gameState.customerIsReady === true) {
let Xposition = gameState.currentMeal.length;

switch(food) {
case 'Burger':
gameState.currentMeal.create(Xposition, customer.y, 'Burger');
break;
case 'Fries':
gameState.currentMeal.create(Xposition, customer.y, 'Fries');
break;
case 'Shake':
gameState.currentMeal.create(Xposition, customer.y, 'Shake');
break;
}
//step 28
gameState.currentMeal.fullnessValue = fullnessValue;

//step 29.. help!
for (let i = 0; i < gameState.currentCustomer.fullnessCapacity; i++) {
gameState.currentMeal.fullnessValue.forEach();
}

}
}
``````

Hello, and welcome to the forums!

This part can be a little confusing because it’s laying the groundwork for what you’ll be doing in the next steps. Without knowing what you’ll be doing, it’s much harder to interpret exactly what/why it’s asking you to do something. I found that reading ahead to get a feel for what’s coming helped a lot with the way this project was written.

In this case, you’ll be coloring fullness indicator blocks to let the player know how close (or over) they are.
`gameState.currentCustomer.fullnessCapacity` is the total number of blocks there will be for the customer.
`gameState.currentMeal.fullnessValue` is the total number of blocks the current combination of food items could occupy. Since it’s possible to add too much food for the customer, this number may be greater than how many blocks the customer has for their fullnessCapacity.

What it wants you to do is create a loop that counts up to the gameState.currentMeal.fullnessValue of the meal, and then inside the loop add a condition to make sure the count isn’t higher than the number of blocks the customer has (fullnessCapacity) because you can’t color in the blocks that don’t exist if the meal is greater than the customer’s fullnessCapacity.

Hopefully I didn’t just confuse you further. To be clearer, right now your loop isn’t counting up to the correct variable. It needs to count towards `gameState.currentMeal.fullnessValue`. Then inside the loop, you need to add an `if` statement to make sure that `i` is still less than `gameState.currentCustomer.fullnessCapacity` to prevent trying to set the coloring of blocks that don’t exist if the customer is overfed.

I’ll leave you with one final hint that will hopefully save you a lot of frustration during future testing. Your interpretation of Step #28 is slightly off. They wanted you to add the `fullnessValue` to `gameState.currentMeal.fullnessValue`, but you’re currently setting the value without addition.

1 Like

Hi Selecall,

That’s great, I do understand what you’re saying… I think … However, I’ve followed the instructions down to step 34, so the keys work, the food sprites get added in and all appears well until it’s not…

Let me explain, if a customers capacity is for example 6, and I add a burger worth 5 points, then it works perfectly. The appropriate blocks change colour to a different shade of yellow as intended. However, if I choose a food that would make it go beyond the capacity, the game break and comes up with this error:
`undefined is not an object (evaluating 'gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle')`

The below is the full code, and the above error relates to the first Else If statement, which is strange because it should not execute this line unless the customer is perfectly full.

Also, no changes occur to the meter blocks if the customer is purposely fed the right amount…

``````      //step 29
for (let i = 0; i < gameState.currentMeal.fullnessValue; i++) {
if (i < gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xFFFA81);

} else if (i === gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0x2EB94E);

} else if (i > gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xDB533A);
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0xB92E2E);

}
}
``````

Full placeFood() for reference I guess?

Summary
``````placeFood(food, fullnessValue) {
if (gameState.currentMeal.children.entries.length < 3 && gameState.customerIsReady === true) {
let Xposition = gameState.currentMeal.length;

switch(food) {
case 'Burger':
gameState.currentMeal.create(Xposition, gameState.cam.midPoint.y, 'Burger');
break;
case 'Fries':
gameState.currentMeal.create(Xposition, gameState.cam.midPoint.y, 'Fries');
break;
case 'Shake':
gameState.currentMeal.create(Xposition, gameState.cam.midPoint.y, 'Shake');
break;
}
//step 28
gameState.currentMeal.fullnessValue += fullnessValue;

//step33
gameState.sfx.placeFood.play();

//step 29
for (let i = 0; i < gameState.currentMeal.fullnessValue; i++) {
if (i < gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xFFFA81);

} else if (i === gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0x2EB94E);

} else if (i > gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xDB533A);
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0xB92E2E);

}
}
}
}
``````

Hello,

The issue is that `i` can be larger than `gameState.currentCustomer.fullnessCapacity` so there aren’t enough `gameState.currentCustomer.fullnessMeterBlocks[i]` to cover it in that case.

Once `i` is larger than `gameState.currentCustomer.fullnessCapacity`, then the next time you try to use the `.setFillStyle()` method on `gameState.currentCustomer.fullnessMeterBlocks[i]`, it will produce an error. That block doesn’t exist so it doesn’t have the method.

There are a few ways you can deal with it, but the original way that the instructions intended was something like this:

``````for loop like you have now
if condition to make sure i is less than the capacity
if / else if / else conditions here based on comparisons of gameState.currentMeal.fullnessValue and gameState.currentCustomer.fullnessCapacity
so you can determine the block colors
end if / else if / else.
end if
end for loop
``````

I wrote it like this to give you a better idea of what I meant before. The first `if` will act as a guard to make sure the inner `if` `else if` `else` conditions are only evaluated if `i` is in the right range.

As I said, this strategy is just how they originally wrote the instructions, but there are different ways to accomplish the same thing.

I mentioned the inner `if` conditions were based on comparisons of `gameState.currentMeal.fullnessValue` and `gameState.currentCustomer.fullnessCapacity` because my interpretation of what they want is if the customer is still under capacity, they want all the blocks to be a certain color and not just the ones under. Same if the meal was perfect - all the blocks should be the same nice color to indicate success. Likewise if they are overfed, then everything would be red.

Selectall… you are an absolute legend!

Rewrote it, and it appears to work perfectly fine!

I will no doubt contact you or more help as I progress down these steps…

``````placeFood(food, fullnessValue) {
if (gameState.currentMeal.children.entries.length < 3 && gameState.customerIsReady === true) {
let Xposition = gameState.cam.midPoint.x;

switch(food) {
case 'Burger':
gameState.currentMeal.create(Xposition - 90, gameState.cam.midPoint.y, 'Burger').setScale(0.5);
break;
case 'Fries':
gameState.currentMeal.create(Xposition, gameState.cam.midPoint.y, 'Fries').setScale(0.5);
break;
case 'Shake':
gameState.currentMeal.create(Xposition + 90, gameState.cam.midPoint.y, 'Shake').setScale(0.5);
break;
}
//step 28
gameState.currentMeal.fullnessValue += fullnessValue;

//step33
gameState.sfx.placeFood.play();

//step 29
for (let i = 0; i < gameState.currentMeal.fullnessValue; i++) {
if (i < gameState.currentCustomer.fullnessCapacity) {
if (gameState.currentMeal.fullnessValue < gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xFFFA81);

} else if (gameState.currentMeal.fullnessValue === gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0x2EB94E);

} else if (gameState.currentMeal.fullnessValue > gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xDB533A);
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0xB92E2E);
}
}
}
}
}
``````
1 Like

Nicely done! This is a really tough project and you’re making great progress!

Sounds good

My man… I feel like I need your help once more…
Now I’m stuck at step 36…
So I’m asked to create a check for Enter, which I did as you can see below, and “move customer line”, which I assume means to call on the method I created in the previous step called moveCustomerLine.

`````` if (Phaser.Input.Keyboard.JustDown(gameState.keys.Enter)) {
console.log('enter');
this.moveCustomerLine();
}
}
``````

However, I get an error:

TypeError: undefined is not an object (evaluating ‘gameState.currentCustomer.meterContainer.visible = true;’)

And it relates to the onComplete from a tween from step 10, and my code for that is:

`````` if (gameState.readyForNextOrder === true) {
{
targets: gameState.currentCustomer,
duration: 100,
delay: 100,
angle: 90,
x: gameState.player.x,
ease: 'Power2',
onComplete: function() {
gameState.currentCustomer.meterContainer.visible = true;
}
}
);
}
``````

I feel like I’m moving at snail pace now… and it doesn’t help that the step descriptions have become a little less descriptive and therefore a bit more confusing…

Thanks for any help on this selectall!

That definitely happens, especially on this project because there are so many moving parts.

Before you add the tween and after you set the new value of `gameState.currentCustomer`, try adding a console.log() of it to see what you’re dealing with. Does it have the information you expect right now?

If it doesn’t, then you’ll need to figure out why `gameState.customers.children.entries[gameState.customersServedCount]` doesn’t have the value you expect. In that case, you could console.log() the `entries` array and `customersServedCount` and go from there if value is off.

Assuming the snippet you posted is in the `update()` function, I’m not seeing anything obvious from this, so hopefully the logs will help the investigation.

Hi Selectall,

Logging customerServedCount works fine, it goes from 0 to 1. However, logging the entries array just gives me a huge list of things, and I’m unsure of what to look at really…

My code up to this point, if you feel like you want to inspect, and maybe find something…:

Summary
``````const gameState = {
score: 0,
starRating: 5,
currentWaveCount: 1,
cam: {},
gameSpeed: 3,
currentMusic: {},
totalWaveCount: 3,
countdownTimer: 1500,
}

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

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

`\${baseURL}audio/sfx/placeFood.ogg`,
`\${baseURL}audio/sfx/placeFood.mp3`
]); // Credit: "action_02.wav" by dermotte: https://freesound.org/people/dermotte

`\${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

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

`\${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

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

`\${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.play({ loop: true });

// Assign SFX
gameState.sfx = {};

// 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);

// Create player and tray sprites

// 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
this.generateWave();

//step 18
//step 19
gameState.currentMeal.fullnessValue = 0;

//step 24

}

update() {
//step 10
{
targets: gameState.currentCustomer,
duration: 100,
delay: 100,
angle: 90,
x: gameState.player.x,
ease: 'Power2',
onComplete: function() {
//step 23
gameState.currentCustomer.meterContainer.visible = true;

}
}
);
}
//step 34
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)) {
console.log('enter');
this.moveCustomerLine();
}
}
}

/* WAVES */
// Generate wave
generateWave() {
// Add the total number of customers per wave here:
gameState.totalCustomerCount = Math.ceil(Math.random() * gameState.currentWaveCount);

this.updateCustomerCountText();

for (let i = 0; i < gameState.totalCustomerCount; i++) {
let customerContainer = this.add.container(gameState.cam.worldView.right + (200 * i), gameState.cam.worldView.bottom - 140);

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

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

//step 7

// Fullness meter container

// 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
//step 20
//let meterWidth = 200;
let meterWidth = customerContainer.fullnessCapacity * 10;
customerContainer.meterContainer = this.add.container(0, customer.y + (meterWidth / 2));

// Add the customerContainer.meterContainer to customerContainer
//step 21

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

// 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;

// 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;
}

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

updateCustomerCountText() {
gameState.customerCountText.setText(`Customers left: \${gameState.customersLeftCount}`);
}

placeFood(food, fullnessValue) {
if (gameState.currentMeal.children.entries.length < 3 && gameState.customerIsReady === true) {
let Xposition = gameState.cam.midPoint.x;

switch(food) {
case 'Burger':
gameState.currentMeal.create(Xposition - 90, gameState.cam.midPoint.y, 'Burger').setScale(0.5);
break;
case 'Fries':
gameState.currentMeal.create(Xposition, gameState.cam.midPoint.y, 'Fries').setScale(0.5);
break;
case 'Shake':
gameState.currentMeal.create(Xposition + 90, gameState.cam.midPoint.y, 'Shake').setScale(0.5);
break;
}
//step 28
gameState.currentMeal.fullnessValue += fullnessValue;

//step33
gameState.sfx.placeFood.play();

//step 29
for (let i = 0; i < gameState.currentMeal.fullnessValue; i++) {
if (i < gameState.currentCustomer.fullnessCapacity) {
if (gameState.currentMeal.fullnessValue < gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xFFFA81);
} else if (gameState.currentMeal.fullnessValue === gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0x2EB94E);
} else if (gameState.currentMeal.fullnessValue > gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xDB533A);
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0xB92E2E);
}
}
}
}
}

moveCustomerLine() {
gameState.currentMeal.clear(true);
gameState.currentMeal.fullnessValue = 0;

}
}
``````

I tried out your code and there were more clues hidden in those logs.

`gameState.currentCustomer` may have looked good for the first customer, but as soon as you got to the second customer, it logs as `undefined`.

As you mentioned, `customerServedCount` goes from 0 to 1, but there isn’t another customer in `gameState.customers.children.entries` to get. You may not have gotten to the part of the game where you’re checking for end state since it was being done in waves, but it is curious that you only have one customer.

If we log `gameState` to see what properties we have, there is one called `totalCustomerCount`, which also shows as 1, so it makes sense there is only 1 entry, even if it isn’t what you want.

Since we know totalCustomerCount gets set to 1 and there is only 1 customer created, you need to double check where that gets set and they get generated, which is in `generateWave()`. You generate a random number for the number of customers for the wave, but it will always be 1 for wave 1 with your current formula. Consider adjusting this

You’ll be adding logic to handle when you finished the wave later, but right now your ability to test is limited since you only have 1 customer.

Selectall, you are a god send!
I’ve adjusted the formula to determine the number of customers in a wave to:

``````  generateWave() {
// Add the total number of customers per wave here:
gameState.totalCustomerCount = Math.ceil((Math.random() * 10) * gameState.currentWaveCount);
``````

I think this is how it was meant to look, but the step and the hint had me a little confused. I think it worked as intended but limiting the amount of customer per wave to not be higher than the wave level, however it meant wave 1 would always cause problems, until I reached the later steps where waves are destroyed etc.

Again, thank you very much for your help, you gave me an idea where to look!

Hi Selectall,

Still trying to progress trough this believe it or not…

Got down to step 39, so not long left now, and just struggling with some logic.

I’m asked to create tweens for the customers to be served, however I don’t see a way of storing that to use as a target for the tween. I’m also not entirely sure if I’m placing it correctly within the code…

Below is my update method

Summary
``````  update() {
//step 10

for(let i = 0; i < gameState.customersServedCount; i++){
{
targets: gameState.currentCustomer,
duration: 750,
x: '-=300',
angle: 0,
onStart: () => {
gameState.customers.children.entries[i].meterContainer.visible = false;
}
});
//step 28
targets: gameState.customers.children.entries[i],
duration: 750,
x: '-=300',
angle: 0
});
}

{
targets: gameState.currentCustomer,
duration: 100,
delay: 100,
angle: 90,
x: gameState.player.x,
ease: 'Power2',
onComplete: function() {
//step 23
gameState.currentCustomer.meterContainer.visible = true;
}
}
);
//step 39
for (let i = 0; i < gameState.customersLeftCount; i++) {
{
targets: ,
delay: 200,
x: '-=200',
duration: 1500
}
)
}
}
``````

Any help would be appreciated.

You’re getting really close now. Some hints for handling this part:

• The loop runs once for each customer remaining
• You have access to the customers via the `gameState.customers.children.entries` array, but you’ll need to use some math to figure out the right index to use
• There are different methods to calculate the right index, but consider some of the variables you have and decide how you want to go about it. Some of them to consider
`gameState.customersServedCount`
`gameState.customersLeftCount`
`gameState.customers.children.entries.length`
`i`

Once you have the right index, then you can use that to get the target that you need for the tween. Maybe even store the customer object in a locally scoped variable for convenience. Something like

``````for loop that you have
let nextCustomer = gameState.customers.children.entries[magic_index_calculation_here];
end for
``````

I don’t recall if the instructions tell you exactly how they want you to calculate the index to use, but hopefully the hints above will get you going in the right direction to calculate it.

Here is how I did it

You shouldn’t dig deeper in here until you’ve already tried it yourself.

Only open if you're truly stuck

Are you sure?

``````let nextCustomer = gameState.customers.children.entries[gameState.customersServedCount + i + 1];
``````

Haha I like your spoiler derail…

I ended up having to look up your spoiler anyway as it appears I didn’t quite understand the pre-written code a 100% in relation to how the customer container was created, and so couldn’t understand my way around the tween targets… I think I get it now though!

Thanks a lot, once again

Oh Selectall! I summon thee!.. ekhm… Hi, I need your guidance.

I’m on step 45… now… first two points a bit confusing, as there is pre-written code that already does that? - So I skipped that and I’m on the point 3 and 4, creating the timer, and shrinking the timer.

So I thought I would start the timer within the tween to when a customer is facing the chef with onStart, code below… but I don’t really know how to go about the whole ‘timer’, because I initially thought I could change the `gameState.currentCustomer.timerMeterBody.width`. But I’ve not had luck, and looking at documentation it’s not possible? So yea… don’t know how to create a timer, and shrink the bar…

``````this.add.tween(
{
targets: gameState.currentCustomer,
duration: 1000,
delay: 100,
angle: 90,
x: gameState.player.x,
ease: 'Power2',
onStart: () => {
console.log(gameState.currentCustomer.timerMeterBody.width);
},
onComplete: function() {
//step 23
gameState.currentCustomer.meterContainer.visible = true;
}
}
);
``````

Customers won’t wait forever to be served. Express the concept of customers’ patience in your game using a timed meter that goes down to zero.

• Draw a background for each customer’s timer meter under the fullness meter
• Draw a bar to represent the timer
• Create a timer once the customer has moved up to the chef.
• Shrink the timer bar as the customer loses patience
• Change the color of the timer as the customer is closer to leaving: green ( `0x3ADB40` ) when there’s lots of time, orange ( `0xFF9D00` ) at the 25% mark, and red ( `0xDB533A` ) if the timer is 75% complete.
• Automatically run `moveCustomerLine()` when the timer reaches zero.
• Remove the timer if the customer has been manually served before time runs out.

Full code for reference if you need…

Summary
``````const gameState = {
score: 0,
starRating: 0,
currentWaveCount: 1,
cam: {},
gameSpeed: 3,
currentMusic: {},
totalWaveCount: 3,
countdownTimer: 1500,
}

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

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

`\${baseURL}audio/sfx/placeFood.ogg`,
`\${baseURL}audio/sfx/placeFood.mp3`
]); // Credit: "action_02.wav" by dermotte: https://freesound.org/people/dermotte

`\${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

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

`\${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

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

`\${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.play({ loop: true });

// Assign SFX
gameState.sfx = {};

// 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);

// Create player and tray sprites

// 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
this.generateWave();

//step 18
//step 19
gameState.currentMeal.fullnessValue = 0;

//step 24

this.drawStars();
}

update() {
//step 10

for(let i = 0; i < gameState.customersServedCount; i++){
{
targets: gameState.currentCustomer,
duration: 750,
x: '-=300',
angle: 0,
onStart: () => {
gameState.customers.children.entries[i].meterContainer.visible = false;
}
});
//step 28
targets: gameState.customers.children.entries[i],
duration: 750,
x: '-=300',
angle: 0
});
}

{
targets: gameState.currentCustomer,
duration: 1000,
delay: 100,
angle: 90,
x: gameState.player.x,
ease: 'Power2',
onStart: () => {
console.log(gameState.currentCustomer.timerMeterBody.width);
},
onComplete: function() {
//step 23
gameState.currentCustomer.meterContainer.visible = true;
}
}
);
//step 39
for (let i = 0; i < gameState.customersLeftCount; i++) {
let nextCustomer = gameState.customers.children.entries[gameState.customersServedCount + i + 1];
{
targets: nextCustomer,
delay: 200,
x: '-=200',
duration: 1500
}
)
}

}
//step 34
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)) {
this.moveCustomerLine();
this.updateCustomerCountText();
}
}
}

drawStars() {
gameState.starGroup.children.entries.forEach((star) => { star.destroy()});
for (let i = 0; i < gameState.starRating; i++) {
let spacer = i * 50;
gameState.starGroup.create(20 + spacer, 20, 'Star-full').setScale(.5).setOrigin(0);
}
}

/* WAVES */
// Generate wave
generateWave() {
console.log('Looped: ')
// 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++) {
let customerContainer = this.add.container(gameState.cam.worldView.right + (200 * i), gameState.cam.worldView.bottom - 140);

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

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

//step 7

// Fullness meter container

// 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
//step 20
//let meterWidth = 200;
let meterWidth = customerContainer.fullnessCapacity * 10;
customerContainer.meterContainer = this.add.container(0, customer.y + (meterWidth / 2));

// Add the customerContainer.meterContainer to customerContainer
//step 21

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

//step 45??

// 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;

// 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;
}

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

updateCustomerCountText() {
gameState.customerCountText.setText(`Customers left: \${gameState.customersLeftCount}`);
}

placeFood(food, fullnessValue) {
if (gameState.currentMeal.children.entries.length < 3 && gameState.customerIsReady === true) {
let Xposition = gameState.cam.midPoint.x;

switch(food) {
case 'Burger':
gameState.currentMeal.create(Xposition - 90, gameState.cam.midPoint.y, 'Burger').setScale(0.5);
break;
case 'Fries':
gameState.currentMeal.create(Xposition, gameState.cam.midPoint.y, 'Fries').setScale(0.5);
break;
case 'Shake':
gameState.currentMeal.create(Xposition + 90, gameState.cam.midPoint.y, 'Shake').setScale(0.5);
break;
}
//step 28
gameState.currentMeal.fullnessValue += fullnessValue;

//step33
gameState.sfx.placeFood.play();

//step 29
for (let i = 0; i < gameState.currentMeal.fullnessValue; i++) {
if (i < gameState.currentCustomer.fullnessCapacity) {
if (gameState.currentMeal.fullnessValue < gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xFFFA81);
} else if (gameState.currentMeal.fullnessValue === gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0x2EB94E);
} else if (gameState.currentMeal.fullnessValue > gameState.currentCustomer.fullnessCapacity) {
gameState.currentCustomer.fullnessMeterBlocks[i].setFillStyle(0xDB533A);
gameState.currentCustomer.fullnessMeterBlocks[i].setStrokeStyle(2, 0xB92E2E);
}
}
}
}
}

if (fullnessValue === fullnessCapacity) {
gameState.sfx.servingCorrect.play();
gameState.score += 100;
gameState.scoreText.setText(`Score: \${gameState.score}`);
if (gameState.starRating < 5) {
gameState.starRating++;
if (gameState.starRating === 5) {
gameState.sfx.fiveStars.play();
};
};

} else if (fullnessValue < fullnessCapacity) {
gameState.currentCustomer.list[0].setTint(0xDB533A);
gameState.sfx.servingIncorrect.play();
gameState.starRating -= 2;
if ( gameState.starRating < 0) {
gameState.starRating = 0;
}
} else if (fullnessValue > fullnessCapacity) {
gameState.currentCustomer.list[0].setTint(0xDB9B3A);
gameState.sfx.servingEmpty.play();
gameState.starRating -= 1;
if ( gameState.starRating < 0) {
gameState.starRating = 0;
}
}
this.drawStars();
}

moveCustomerLine() {