For the upcoming midterm project, I decided to code an interactive game. Now, when it came to choosing a game, I was reminded of a game I used to play when I was younger, Cooking Mama, which revolved around making different kinds of recipes. That, along with my own personal bias towards baked goods, gave me an idea. I am planning to create a memory game that is set in a bakery. The game itself is quite striaghtforward, with the user selecting a recipe, then having to select the right ingredients within the given time frame in order to make it
The game flow starts with a menu from which the user has to select an item to bake. They are then shown the ingredients required for a few seconds in order to memorize them, then are required to select those ingredients from the shelf (within a given time limit). If they manage, the item is baked, and they are shown the winning end screen. If they fail to select all the ingredients, or select the wrong ingredients, they are shown the failure end screen.
I have managed so far to create a base version of the game, just to see whether I would actually be able to code it or not. My current code consists of a Game class, which keeps track of which dish is chosen, which ingredients are needed, and whether you won or lost. In order to play the game, the Game class also stores the different “stages” of the game, namely the start screen, menu, memory phase, selection phase, and the result phase.
this.state = "start"; // start, menu, memory, selection, result, baking, end
this.selectedDish = null;
this.correctIngredients = [];
this.ingredientShelf = [];
this.selectedIngredients = [];
this.timer = 500; // Updated timer for selection
this.showPlayAgainButton = false; // Flag to show "Play Again" button
this.showWinningMessage = false; // Flag to show winning message
this.showFailureMessage = false; // Flag to show failure message
if (this.state === "start") {
} else if (this.state === "menu") {
} else if (this.state === "memory") {
} else if (this.state === "selection") {
} else if (this.state === "result") {
} else if (this.state === "baking") {
} else if (this.state === "end") {
if (this.state === "start") {
} else if (this.state === "menu") {
this.handleMenuSelection();
} else if (this.state === "selection") {
this.handleIngredientSelection();
} else if (this.state === "end" && this.showPlayAgainButton) {
this.state = "menu"; // Ensure it goes back to the menu
textAlign(CENTER, CENTER);
text("Press Anywhere to Start", width / 2, height / 2);
textAlign(CENTER, CENTER);
text("Choose a Dish:", width / 2, height / 4);
for (let dish of Object.keys(ingredientsData)) {
text(dish, width / 2, y);
for (let dish of Object.keys(ingredientsData)) {
if (mouseY > y - 15 && mouseY < y + 15) {
this.selectedDish = dish;
this.correctIngredients = ingredientsData[dish];
setTimeout(() => this.state = "selection", 3000); // Show memory phase briefly
this.createIngredientShelf();
textAlign(CENTER, CENTER);
text("Memorize These Ingredients!", width / 2, 50);
for (let ingredient of this.correctIngredients) {
ellipse(x, height / 2, 50);
text(ingredient, x, height / 2 + 40);
createIngredientShelf() {
let allIngredients = ["Flour", "Egg", "Chocolate", "Sugar", "Butter", "Milk", "Vanilla", "Apple", "Salt", "Baking Powder", "Lemon", "Cinnamon"];
this.ingredientShelf = [];
for (let ingredient of allIngredients) {
this.ingredientShelf.push(new Ingredient(x, height - 100, ingredient));
text(`Select the ingredients for ${this.selectedDish}`, width / 2, 50);
text(`Time Left: ${Math.ceil(this.timer / 60)}s`, width - 100, 50);
fill(200, 200, 200); // Shelf background
rect(0, height - 150, width, 150);
for (let ingredient of this.ingredientShelf) {
handleIngredientSelection() {
for (let ingredient of this.ingredientShelf) {
if (ingredient.isClicked(mouseX, mouseY)) {
ingredient.selected = !ingredient.selected;
if (ingredient.selected) {
this.selectedIngredients.push(ingredient.name);
this.selectedIngredients = this.selectedIngredients.filter(i => i !== ingredient.name);
if (this.selectedIngredients.length === this.correctIngredients.length) {
let isCorrect = this.selectedIngredients.sort().toString() === this.correctIngredients.sort().toString();
textAlign(CENTER, CENTER);
this.showWinningMessage = true;
this.showFailureMessage = false;
this.showPlayAgainButton = true; // Show play again button
this.showFailureMessage = true;
this.showWinningMessage = false;
this.showPlayAgainButton = true; // Show play again button immediately
textAlign(CENTER, CENTER);
text("Baking...", width / 2, height / 2);
text("Ding! Your dish is ready!", width / 2, height / 2 + 50);
if (this.showWinningMessage) {
textAlign(CENTER, CENTER);
text(`Your ${this.selectedDish} is now ready!`, width / 2, height / 2);
this.showPlayAgainButton = true; // Immediately show the Play Again button
if (this.showFailureMessage) {
textAlign(CENTER, CENTER);
text("Oh no! Those were the wrong ingredients!", width / 2, height / 2);
if (this.showPlayAgainButton) {
// Display "Play Again" button
rect(width / 2 - 100, height / 2 + 80, 200, 50);
text("Play Again", width / 2, height / 2 + 105);
this.selectedDish = null;
this.correctIngredients = [];
this.ingredientShelf = [];
this.selectedIngredients = [];
this.timer = 310; // Reset timer
this.showPlayAgainButton = false; // Reset play again button
this.showWinningMessage = false; // Reset winning message
this.showFailureMessage = false; // Reset failure message
class Game {
constructor() {
this.state = "start"; // start, menu, memory, selection, result, baking, end
this.selectedDish = null;
this.correctIngredients = [];
this.ingredientShelf = [];
this.selectedIngredients = [];
this.timer = 500; // Updated timer for selection
this.showPlayAgainButton = false; // Flag to show "Play Again" button
this.showWinningMessage = false; // Flag to show winning message
this.showFailureMessage = false; // Flag to show failure message
}
display() {
if (this.state === "start") {
this.showStartScreen();
} else if (this.state === "menu") {
this.showMenu();
} else if (this.state === "memory") {
this.showMemory();
} else if (this.state === "selection") {
this.showSelection();
} else if (this.state === "result") {
this.showResult();
} else if (this.state === "baking") {
this.showBaking();
} else if (this.state === "end") {
this.showEndScreen();
}
}
handleClick() {
if (this.state === "start") {
this.state = "menu";
} else if (this.state === "menu") {
this.handleMenuSelection();
} else if (this.state === "selection") {
this.handleIngredientSelection();
} else if (this.state === "end" && this.showPlayAgainButton) {
this.resetGame();
this.state = "menu"; // Ensure it goes back to the menu
}
}
showStartScreen() {
textAlign(CENTER, CENTER);
textSize(32);
text("Press Anywhere to Start", width / 2, height / 2);
}
showMenu() {
textAlign(CENTER, CENTER);
textSize(24);
text("Choose a Dish:", width / 2, height / 4);
let y = 200;
for (let dish of Object.keys(ingredientsData)) {
text(dish, width / 2, y);
y += 50;
}
}
handleMenuSelection() {
let y = 200;
let index = 0;
for (let dish of Object.keys(ingredientsData)) {
if (mouseY > y - 15 && mouseY < y + 15) {
this.selectedDish = dish;
this.correctIngredients = ingredientsData[dish];
this.state = "memory";
setTimeout(() => this.state = "selection", 3000); // Show memory phase briefly
this.createIngredientShelf();
}
y += 50;
index++;
}
}
showMemory() {
textAlign(CENTER, CENTER);
textSize(24);
text("Memorize These Ingredients!", width / 2, 50);
let x = 100;
for (let ingredient of this.correctIngredients) {
fill(200, 100, 100);
ellipse(x, height / 2, 50);
textSize(14);
text(ingredient, x, height / 2 + 40);
x += 150;
}
}
createIngredientShelf() {
let allIngredients = ["Flour", "Egg", "Chocolate", "Sugar", "Butter", "Milk", "Vanilla", "Apple", "Salt", "Baking Powder", "Lemon", "Cinnamon"];
this.ingredientShelf = [];
let x = 100;
for (let ingredient of allIngredients) {
this.ingredientShelf.push(new Ingredient(x, height - 100, ingredient));
x += 100;
}
}
showSelection() {
textSize(24);
text(`Select the ingredients for ${this.selectedDish}`, width / 2, 50);
text(`Time Left: ${Math.ceil(this.timer / 60)}s`, width - 100, 50);
this.timer--;
if (this.timer <= 0) {
this.state = "result";
}
this.showShelf();
}
showShelf() {
fill(200, 200, 200); // Shelf background
rect(0, height - 150, width, 150);
for (let ingredient of this.ingredientShelf) {
ingredient.display();
}
}
handleIngredientSelection() {
for (let ingredient of this.ingredientShelf) {
if (ingredient.isClicked(mouseX, mouseY)) {
ingredient.selected = !ingredient.selected;
if (ingredient.selected) {
this.selectedIngredients.push(ingredient.name);
} else {
this.selectedIngredients = this.selectedIngredients.filter(i => i !== ingredient.name);
}
}
}
if (this.selectedIngredients.length === this.correctIngredients.length) {
this.state = "result";
}
}
showResult() {
let isCorrect = this.selectedIngredients.sort().toString() === this.correctIngredients.sort().toString();
textAlign(CENTER, CENTER);
textSize(32);
if (isCorrect) {
this.showWinningMessage = true;
this.showFailureMessage = false;
this.state = "baking";
setTimeout(() => {
this.state = "end";
this.showPlayAgainButton = true; // Show play again button
}, 3000);
} else {
this.showFailureMessage = true;
this.showWinningMessage = false;
this.state = "end";
this.showPlayAgainButton = true; // Show play again button immediately
}
}
showBaking() {
textAlign(CENTER, CENTER);
textSize(32);
text("Baking...", width / 2, height / 2);
setTimeout(() => {
text("Ding! Your dish is ready!", width / 2, height / 2 + 50);
}, 2000);
}
showEndScreen() {
if (this.showWinningMessage) {
textAlign(CENTER, CENTER);
textSize(32);
text(`Your ${this.selectedDish} is now ready!`, width / 2, height / 2);
this.showPlayAgainButton = true; // Immediately show the Play Again button
}
if (this.showFailureMessage) {
textAlign(CENTER, CENTER);
textSize(32);
text("Oh no! Those were the wrong ingredients!", width / 2, height / 2);
}
if (this.showPlayAgainButton) {
// Display "Play Again" button
fill(200);
rect(width / 2 - 100, height / 2 + 80, 200, 50);
fill(0);
textSize(24);
text("Play Again", width / 2, height / 2 + 105);
}
}
resetGame() {
this.selectedDish = null;
this.correctIngredients = [];
this.ingredientShelf = [];
this.selectedIngredients = [];
this.timer = 310; // Reset timer
this.showPlayAgainButton = false; // Reset play again button
this.showWinningMessage = false; // Reset winning message
this.showFailureMessage = false; // Reset failure message
}
}
class Game {
constructor() {
this.state = "start"; // start, menu, memory, selection, result, baking, end
this.selectedDish = null;
this.correctIngredients = [];
this.ingredientShelf = [];
this.selectedIngredients = [];
this.timer = 500; // Updated timer for selection
this.showPlayAgainButton = false; // Flag to show "Play Again" button
this.showWinningMessage = false; // Flag to show winning message
this.showFailureMessage = false; // Flag to show failure message
}
display() {
if (this.state === "start") {
this.showStartScreen();
} else if (this.state === "menu") {
this.showMenu();
} else if (this.state === "memory") {
this.showMemory();
} else if (this.state === "selection") {
this.showSelection();
} else if (this.state === "result") {
this.showResult();
} else if (this.state === "baking") {
this.showBaking();
} else if (this.state === "end") {
this.showEndScreen();
}
}
handleClick() {
if (this.state === "start") {
this.state = "menu";
} else if (this.state === "menu") {
this.handleMenuSelection();
} else if (this.state === "selection") {
this.handleIngredientSelection();
} else if (this.state === "end" && this.showPlayAgainButton) {
this.resetGame();
this.state = "menu"; // Ensure it goes back to the menu
}
}
showStartScreen() {
textAlign(CENTER, CENTER);
textSize(32);
text("Press Anywhere to Start", width / 2, height / 2);
}
showMenu() {
textAlign(CENTER, CENTER);
textSize(24);
text("Choose a Dish:", width / 2, height / 4);
let y = 200;
for (let dish of Object.keys(ingredientsData)) {
text(dish, width / 2, y);
y += 50;
}
}
handleMenuSelection() {
let y = 200;
let index = 0;
for (let dish of Object.keys(ingredientsData)) {
if (mouseY > y - 15 && mouseY < y + 15) {
this.selectedDish = dish;
this.correctIngredients = ingredientsData[dish];
this.state = "memory";
setTimeout(() => this.state = "selection", 3000); // Show memory phase briefly
this.createIngredientShelf();
}
y += 50;
index++;
}
}
showMemory() {
textAlign(CENTER, CENTER);
textSize(24);
text("Memorize These Ingredients!", width / 2, 50);
let x = 100;
for (let ingredient of this.correctIngredients) {
fill(200, 100, 100);
ellipse(x, height / 2, 50);
textSize(14);
text(ingredient, x, height / 2 + 40);
x += 150;
}
}
createIngredientShelf() {
let allIngredients = ["Flour", "Egg", "Chocolate", "Sugar", "Butter", "Milk", "Vanilla", "Apple", "Salt", "Baking Powder", "Lemon", "Cinnamon"];
this.ingredientShelf = [];
let x = 100;
for (let ingredient of allIngredients) {
this.ingredientShelf.push(new Ingredient(x, height - 100, ingredient));
x += 100;
}
}
showSelection() {
textSize(24);
text(`Select the ingredients for ${this.selectedDish}`, width / 2, 50);
text(`Time Left: ${Math.ceil(this.timer / 60)}s`, width - 100, 50);
this.timer--;
if (this.timer <= 0) {
this.state = "result";
}
this.showShelf();
}
showShelf() {
fill(200, 200, 200); // Shelf background
rect(0, height - 150, width, 150);
for (let ingredient of this.ingredientShelf) {
ingredient.display();
}
}
handleIngredientSelection() {
for (let ingredient of this.ingredientShelf) {
if (ingredient.isClicked(mouseX, mouseY)) {
ingredient.selected = !ingredient.selected;
if (ingredient.selected) {
this.selectedIngredients.push(ingredient.name);
} else {
this.selectedIngredients = this.selectedIngredients.filter(i => i !== ingredient.name);
}
}
}
if (this.selectedIngredients.length === this.correctIngredients.length) {
this.state = "result";
}
}
showResult() {
let isCorrect = this.selectedIngredients.sort().toString() === this.correctIngredients.sort().toString();
textAlign(CENTER, CENTER);
textSize(32);
if (isCorrect) {
this.showWinningMessage = true;
this.showFailureMessage = false;
this.state = "baking";
setTimeout(() => {
this.state = "end";
this.showPlayAgainButton = true; // Show play again button
}, 3000);
} else {
this.showFailureMessage = true;
this.showWinningMessage = false;
this.state = "end";
this.showPlayAgainButton = true; // Show play again button immediately
}
}
showBaking() {
textAlign(CENTER, CENTER);
textSize(32);
text("Baking...", width / 2, height / 2);
setTimeout(() => {
text("Ding! Your dish is ready!", width / 2, height / 2 + 50);
}, 2000);
}
showEndScreen() {
if (this.showWinningMessage) {
textAlign(CENTER, CENTER);
textSize(32);
text(`Your ${this.selectedDish} is now ready!`, width / 2, height / 2);
this.showPlayAgainButton = true; // Immediately show the Play Again button
}
if (this.showFailureMessage) {
textAlign(CENTER, CENTER);
textSize(32);
text("Oh no! Those were the wrong ingredients!", width / 2, height / 2);
}
if (this.showPlayAgainButton) {
// Display "Play Again" button
fill(200);
rect(width / 2 - 100, height / 2 + 80, 200, 50);
fill(0);
textSize(24);
text("Play Again", width / 2, height / 2 + 105);
}
}
resetGame() {
this.selectedDish = null;
this.correctIngredients = [];
this.ingredientShelf = [];
this.selectedIngredients = [];
this.timer = 310; // Reset timer
this.showPlayAgainButton = false; // Reset play again button
this.showWinningMessage = false; // Reset winning message
this.showFailureMessage = false; // Reset failure message
}
}
While building the game, I am currently and further expecting to face challenges. The most prominant being:
- Managing the game states: the game has multiple stages (as I mentioned earlier), and I want to ensure that there are smooth transitions between these stages
- User interaction: the player’s selection should be correctly registered, and the game must check if the chosen ingredients match the correct sets already stored.
- Game reset: the game should clear the previous players seections and reset for a new round automatically
- Graphics creation and implementation: The graphics need to be created, and then also smoothly implemented within the game, not looking patchy or out of place.
The game in it’s current format works, but doesn’t look very appealing. I am currently using circles as placeholders for the ingredients, though I plan to create graphics for the backgrounds, the ingredients, and the start and end screens, as well as an animation for the “baking” scene if the user succeeds. There will also be background music implemented, with a “ding” sound effect if the user succeeds and the item successfully is baked.
Looks like a nice clean implementation with the Game class and using the different states