Concept:
Introducing my latest creation – a memory card game with a unique twist! As one of the most popular games enjoyed by people of all ages in various forms, I wanted to put my own spin on it by incorporating a theme that I feel passionately about – food. The result is a game that is both fun and engaging and adds a personal touch that sets it apart from other versions.
I aim to showcase Pakistani Cuisine through this game, which shares similarities with cuisines from neighboring countries such as Nepal, India, and Sri Lanka. The increasing globalization has led to a rise in the popularity and recognition of desi food. Through this memory game, I hope to introduce players to lesser-known dishes that they may not have come across before. As a result, the unique names of these dishes will stay with them for a long time.
Final Outcome:
Game Code:
Following is the code for the game:
let numMatches = 0; //to see if all matches found and game ends let numTries = 0; //counter to keep track of counts let delayStartFC; //10 card image variables let card1; let card2 ; let card3; let card4; let card5; let card6; let card7; let card8; let card9; let card10; //array variables for image of cards and tiles etc let faces = []; let flippedTiles = []; let tiles = []; let selected = []; let possibleFaces; let startgame; //variables for images and sounds let backgroundImage; let instructionsImage; let endImage; let mymusic; let flipsound; let clicksound; let flipSide; let gameState; //to enter different stages: instructions, game, end let NUM_COLS = 4; let NUM_ROWS = 5; function preload() { //loading all images and sounds flipSide = loadImage("back.jpg"); card1 = loadImage("card1.jpg"); card2 = loadImage("card2.jpg"); card3 = loadImage("card3.jpg"); card4 = loadImage("card4.jpg"); card5 = loadImage("card5.jpg"); card6 = loadImage("card6.jpg"); card7 = loadImage("card7.jpg"); card8 = loadImage("card8.jpg"); card9 = loadImage("card9.jpg"); card10 = loadImage("card10.jpg"); startgame = loadImage ("startgame.png"); backgroundImage = loadImage ("game.png"); instructionsImage = loadImage("instructions.png") endImage = loadImage("end.jpg"); mymusic = loadSound('Baisara-Beera-Kalpana-Patowary-Papon (mp3cut.net).mp3'); flipsound = loadSound ('Card-flip-sound-effect-1.mp3'); clicksound = loadSound('mixkit-game-click-1114.wav'); } function setup() { // Set up canvas and other initialization tasks createCanvas(600, 700); gameState = 'start'; mymusic.loop(); //stays on throughout frameRate(120); } class Tile { constructor(x, y, face) { this.x = x; this.y = y; this.size = 100; this.face = face; this.isFaceUp = false; this.isMatch = false; } draw () { //draws back if not face up otherwise the image of food if (this.isFaceUp) image(this.face, this.x, this.y, this.size, this.size); else image(flipSide, this.x, this.y, this.size, this.size); //black outline of the tiles stroke(0); strokeWeight(3); noFill(); rect(this.x, this.y, this.size, this.size,5); } isUnderMouse(x,y) { //checks if when clicked the tile is under the mouse return x >= this.x && x <= this.x + this.size && y >= this.y && y <= this.y + this.size; } } //function to randomly shuffle the array of tiles with 2 copies each function shuffleArray(array) { let counter = array.length; // while there are elements in the array while (counter > 0) { //selecting a random index let index = Math.floor(Math.random() * counter); // decrementing counter counter--; //swap last element with it var temp = array[counter]; array[counter] = array[index]; array[index] = temp; } } function draw() { if (gameState == 'start') { //displaying image for background of game image(startgame, 0,0,600,700); //start button let c = color('#FF69B4'); fill(c); noStroke(); circle(302.5, 350, 112); fill('black'); textSize(20); textStyle(BOLD); text('Start', 280, 355); } else if (gameState == 'instructions') { //instruction page is an image I made from canva image(instructionsImage,0,0,600,700); } else if (gameState == 'beingSet') { //this is just done once when the start button is clicked faces = [card1, card2, card3, card4, card5, card6, card7, card8, card9, card10]; //storing all images into array // making an array of 2 cards and then randomising possibleFaces = faces.slice(0); for (let i = 0; i < (NUM_COLS * NUM_ROWS) / 2; i++) { // Randomly pick one from the array of remaining faces var randomInd = floor(random(possibleFaces.length)); var face = possibleFaces[randomInd]; // Push twice onto array selected.push(face); selected.push(face); // Remove from array possibleFaces.splice(randomInd, 1); } shuffleArray(selected); //shuffling the array // Creating a Tile object for each card for (var i = 0; i < NUM_COLS; i++) { for (var j = 0; j < NUM_ROWS; j++) { var tileX = (i * 100) + 55+ (i*30); var tileY = (j * 100) + 70 +(j*17); var tileFace = selected.pop(); tiles.push(new Tile(tileX, tileY, tileFace)); } } // Changing the game state to 'playing' gameState = 'playing'; } else if (gameState == 'playing') { // Displaying the background image image(backgroundImage, 0,0,600,700); // Checking if enough time has passed since the last card flip if (delayStartFC && (frameCount - delayStartFC) > 25) { // Hiding the flipped cards that are not matches for (let i = 0; i < tiles.length; i++) { if (!tiles[i].isMatch) tiles[i].isFaceUp = false; } // Resetting the flippedTiles array and delayStartFC variable flippedTiles = []; delayStartFC = null; } // Drawing each tile on the canvas for (let j = 0; j < tiles.length; j++) tiles[j].draw(); // Checking if the game is over if (numMatches == tiles.length/2) gameState = 'end'; } else if (gameState == 'end') { image(endImage, 0,0,600,700); let c = color('#d90166'); fill(c); noStroke(); //play again button circle(302.5, 350, 112); fill('black'); textSize(15); textStyle(BOLD); text('Play Again', 266, 355); textSize(20); //diplaying the tries as a score for game text("You found them all in " + numTries + " tries!", 146,488); } mouseClicked = function() { if(gameState == 'start') { //checking ditance between click and start button let distance = dist(mouseX, mouseY, 302.5, 350); if (distance < 112/2) { //play click sound clicksound.play(); gameState = 'beingSet'; } // checking distance between click and instructions button if (mouseX>220 && mouseX<380 && mouseY>500 && mouseY<540) { clicksound.play(); gameState = 'instructions'; } } else if (gameState == 'playing') { //loop through all the tiles for (let i = 0; i < tiles.length; i++) { let tile = tiles[i]; if (tile.isUnderMouse(mouseX, mouseY)) { // Check if the tile can be flipped (only if less than 2 tiles are flipped and the tile is not already face-up) if (flippedTiles.length < 2 && !tile.isFaceUp) { tile.isFaceUp = true; flipsound.play(); flippedTiles.push(tile); //adds to flippedtiles array if (flippedTiles.length === 2) { numTries++; //increments the tries counter if (flippedTiles[0].face === flippedTiles[1].face) //if they match { flippedTiles[0].isMatch = true; flippedTiles[1].isMatch = true; flippedTiles.length = 0; //empties flipped array because match found numMatches++; } delayStartFC = frameCount; } } } } } else if (gameState == 'instructions') { //clicking the startgame button if (mouseX > 149 && mouseX < 449 && mouseY > 600 && mouseY < 615) { clicksound.play(); gameState = 'beingSet'; } } else if (gameState == 'end') { //clicking restart button let distance = dist(mouseX, mouseY, 302.5, 350); if (distance < 112/2) { clicksound.play(); gameState = 'start'; } } }; }
Process:
Initially, I developed a tile class and successfully displayed the tiles on the screen using the draw function in my program. Although the game was functional, I encountered challenges when attempting to change the game state from the starting page to the playing and end pages. To overcome this hurdle, I referred to the coding examples provided by Professor Mang for changing the game state. However, I had to modify my code to make it compatible with the “if-else” loops used to change the game state. I eventually decided to categorize my game states further and added a new category called “beingSet”, which is only called once before the game begins.
During my coding process, I encountered another obstacle while creating cards for my game using Canva. Initially, the cards included an image, the name of the dish, and a brief description. However, due to the limited dimensions of my game’s canvas, the description on the cards was difficult to read, and it also compromised the visibility of the dish’s name. As a result, I had to recreate all the cards without the description. Despite my efforts, I was disappointed that I could not include the descriptions on the cards.
I just solved another issue in my game a few minutes ago by adding a single line of code:
frameRate(120);
This line of code significantly improved the performance of my game. Previously, as the game progressed towards the end, it would slow down. However, with the addition of this line of code, my game’s speed increased, making it more challenging and an actual test of memory for the players. Nevertheless, I need to investigate why the cards take longer to flip over towards the end, despite the game starting at a normal speed.
Future Improvements:
While I am immensely proud of my game, there is always room for improvement. One area that could be enhanced is by adding a menu with the description of every dish. This could be introduced as an introductory section, where players click on a button and are taken to a menu with forward and back buttons to navigate through an array of images. This would give players the opportunity to familiarize themselves with the dishes, the details of the dish, and the corresponding images before they start playing. This would not only enhance the players’ overall gaming experience but also provide a fun and interactive way to learn about Pakistani cuisine.