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