Cozy Bean Cafe: How the game was made



Cozy Bean Cafe was a game made for the Cozy Autumn Game Jam 2022. Thank you to all who played the game! I appreciate your kind comments. Making the game was a very fun experience, and as the game jam suggested to not stress out, it was also a very chill experience. I tried not to put too many tasks on my plate (or tray, get it?) and kept the game as simple as possible. In this devlog, I will go through how I made the game.


Overview

To play the game, drag and drop items from the counter to the tray at the bottom of the screen to match their positions displayed in the caption bubble in the top right of the screen.



Game Logic

For the game, I used Phaser 3, a Javascript game engine, version 3.55.2. Basically, the tray at the bottom had five different sections, and the items that you placed on those sections had to overlap in order to count as a match. These tray sections were sprites that had setVisible to false but also had setInteractive to allow overlap checking. The food and drink items that you dragged and dropped were also sprites. I always do game functionality before the artwork, so here is an early version of the game with placeholder art. Also, I set the game size to 1024x768 so that the objects were more or less in their final places, plus or minus a few pixels.



The main objects in the game were:

  • goalOrder (string array): The order that must be matched. Positions 0-4 represent the five tray sections illustrated above (position 0 is tray section 1, position 1 is tray section 2, and so on). Positions 0 and 1 are always drinks and positions 2, 3, and 4 are always food. Example: [“drink1”, “drink3”, “food0”, “food4”, “food2”].  drink0 or food0 means that that position on the tray should be left empty.

  • playerOrder (string array): The player’s current order that they are dragging/dropping. Positions 0-4 represent the five tray sections illustrated above (position 0 is tray section 1, position 1 is tray section 2, and so on).

  • incorrectOrder (string array): All the remaining food/drink items that are not in goalOrder.

  • placedIncorrectItems (string array): The incorrect food/drink items that were placed on the tray. This array needs to be empty in order to score and move on to the next order.


The game steps were:

  1. Start timer to 2 minutes (and ending it will go to the game over screen)

  2. Create an order, which sets the goalOrder

  3. Check for overlaps between a food/drink item and a tray section

  4. On an overlap match (food/drink item is on the correct tray section), and if no incorrect items were placed on the tray (placedIncorrectItems is empty), check if the order is complete (goalOrder matches playerOrder)

  5. If order is complete (goalOrder matches playerOrder), go back to step 2


Here are the steps in more detail:

  1. I had an initial time of 2 minutes and used the Phaser timer. In the callback that gets called every second, I decremented the initialTime, and at 0, the game goes to the game over scene. I also made sure to carry over the score to the game over scene.
  2.  goalOrder is an array of strings and positions 0-4 represent the five tray sections. The two positions in the top row of the tray (positions 0 and 1) are always drinks, and the three positions in the bottom row of the tray (positions 2, 3, and 4) are always food. I have four total drink types and four total food types available. I also have drink0 and food0 to represent emptiness or nothing in that tray section.

    Therefore, all the possible food and drinks are:
    • food0, food1, food2, food3, food4, drink0, drink1, drink2, drink3, drink4

    And the tray sections are:

    • tray1, tray2, tray3, tray4, tray5


    I set each order array position individually, starting from 0, and generated a random number between 0 and 4 inclusively to represent drink0 to drink4 or food0 to food4. Also, I wanted to prevent duplicate food or drinks, so if I’m setting position 3, I make sure it doesn’t match position 2, and if it does, I set that position to food0. Here’s an example snippet of what I mean:

    let order3 = `food${this.getRandomNum()}`;
    order[3] = order3 === order[2] ? 'food0' : order3;
    

  3. The food and drink items that the player can drag and drop and the tray sections that the player places the food and drink items on are all arcade physics sprites in Phaser. I used onOverlap to check if every tray section overlapped with every food and drink item. I noticed that you can access the sprite names by using sprite.texture.key. So in the overlap callback function, which gets called when a particular food/drink sprite overlaps with a tray section sprite, I set playerOrder of that particular tray section to that food/drink sprite’s name.
    let trayKey = parseInt(tray.texture.key.slice(-1), 10);
    playerOrder[trayKey - 1] = sprite.texture.key;
    

  4. For any incorrect orders, I added that string to the placedIncorrectOrderItems array.

    if (incorrectOrder.includes(sprite.texture.key)) {
        if (!placedIncorrectItems.includes(sprite.texture.key)) {
            placedIncorrectItems.push(sprite.texture.key);
        }
    }
    

    In the drop function, I also checked the coordinates of the dropped sprite. The food/drink sprite that didn’t belong in the order needed to be off of the tray, so the sprite should be y <= 440 or x <= 170 or x >= 870. This was a very last minute additional check in the game (and I am sure there are better ways to do this), as I noticed a bug in which we could add as many wrong food and drinks as we want on the tray, as long as the goalOrder matched!

  5. I then checked if that dropped item matched what was in the goalOrder.

    if (goalOrder[trayKey - 1] === sprite.texture.key) {

    I also checked if placedIncorrectItems was empty, before I proceeded to check the entire order.

    if (placedIncorrectItems.length === 0) {
         this.checkOrder();
    }
    


  6. The checkOrder function is very simple and just iterates through the goalOrder array if everything is complete.

    for (let i = 0; i < goalOrder.length; i++) {
        if (goalOrder[i] === playerOrder[i]) {
            totalMatched++;
     
            if (totalMatched === goalOrder.length) {
               // play “correct!” animation
               // after half a second, increment the score and reset the tray and make a new order
            }
        }
    


Art

For the artwork, I still have Adobe CS6 (the version before the creative cloud monthly subscriptions, whew!), so I used Adobe Flash CS6, because it uses vectors for art, so I can easily resize things without losing quality. I initially tried to color the game in Adobe Photoshop CS6 with watercolor brushes, as I really wanted to develop my coloring skills with more lighting, shading, texture, etc. Here’s a glimpse of a watercolor brush test:



Unfortunately, the program kept crashing, and coloring was taking too long for the short time available in the game jam. I then switched to all drawing and coloring in Adobe Flash CS6 and stuck with a flat color style. Here’s a glimpse of the line art:



Also, most colors (all except for the lines, chalkboards, background wall, ground, and character skins) were from the autumn glow color palette that the game jam provided. All in all, I think the art turned out okay!



Conclusion

And that wraps it up! I had a lot of fun with this jam. Did you get to play the game? What did you think? If there is anything in particular that you wanted to know more about, let me know in the comments!

Leave a comment

Log in with itch.io to leave a comment.