Crafting Mind Tiles: Building a Multi-Platform Memory App in Record Time!

Click Here To Play Mind Tiles and Dive into the World of Memory Matching!

Ensemble is a low-code platform for app development, offering an easy-to-use and beginner-friendly environment that enables you to configure the user interface through YAML and write logic in JS to create incredible applications. Don't worry if you're new to app development – we've got you covered with clear explanations, handy code examples, and expert tips.

Ensemble provides a range of demo apps, with the "Kitchen Sink" being particularly helpful in showcasing the platform's capabilities.

Get Started By Creating An Ensemble Account

Ensemble's "Kitchen Sink" offers many examples and brakes down the code, making it easier to understand and implement. Below are some of the things available on the "Kitchen Sink" for users.

Check out this screen for yourself: Ensemble Kitchen Sink

Implementing the Home Screen: Let's break it down together to understand its structure and functionality.

Check Out The Home Screen: Home

Styles: We'll give the homepage some cool styles using various parameters like safe area usage, scrollability, and a background image. These styles will make the game interface more immersive and fun!

View:
  onLoad:
    executeCode:
      body: |
        //@code
        initializeGame();
  styles:
    useSafeArea: true
    scrollableView: true
    backgroundImage:
      source: ${env.image_background}

Find Details Here: Styles Widgets

Kitchen Sink Example Here: Different Ways To Style

Body Structure: We'll organize the body of the screen using a Column widget, making it easy to see all the exciting elements in a vertical arrangement.

  body:
    Column:

body:    Column:

Find Details Here: Column

Kitchen Sink Example Here: Column

Text Elements: We'll include text elements on the homepage to introduce you to the game and select your favorite category. We'll carefully choose text styles, such as padding, text alignment, font family, color, and size, so everything looks great and easy to read.

        - Text:
            text: ${env.app_name}
            styles:
              padding: 20
              textAlign: center
              textStyle:
                fontFamily: Pacifico
                color: pink
                fontSize: 40

Kitchen Sink Example Here: Text

Find Styling Details Here: Styles Widgets

Button Elements: Time to pick your category! We'll add multiple buttons, each representing a different category. Whenever you tap a button, we'll make sure to execute the corresponding category functions, storing all the fun icons for your chosen category in the Ensemble storage.

        - Button:
            label: Animals
            onTap:
               executeCode:
                body: |
                  //@code
                  handleCategorySelection("Animals");
                  ensemble.navigateScreen('GamePlay');

Find Details Here: Theme (Button)

Kitchen Sink Example Here: Button

Category Selection and Icon Generation: When you select a category, our "handleCategorySelection(category)" function will work its magic and generate the icons for that category. We'll store them in the Ensemble storage, ready for you to enjoy during gameplay. Our functions like "createAnimalsForTiles()" and "createHalloweenForTiles()" fetch image URLs for each category from this link!

Global: |-
  //@code

  function createAnimalsForTiles() {
        // Image addresses for the tiles
    var icons = [
      env.image_raccoon,
      env.image_octopus,
      env.image_teddybear,
      env.image_dog,
      env.image_lizard,
      env.image_chicken,
      env.image_elephant,
      env.image_sloth
    ];

    return icons;
  }
  function handleCategorySelection(category) {
    //console.log('category :' + category);

    var icons;
    if (category == "Animals") {
      icons = createAnimalsForTiles();
    }
    else if (category == "Halloween") {
      icons = createHalloweenForTiles();
    }
    else if (category == "Emojis") {
      icons = createEmojisForTiles();
    }
    else if (category == "Sports") {
      icons = createSportsForTiles();
    }
    else if (category == "Beauty") {
      icons = createBeautyForTiles();
    }
    ensemble.storage.icons = icons; //store into ensemble storage
    
    //console.log('icons 1 :' + icons);
  }

Global Function:

Find Details Here: Global

Kitchen Sink Example Here: Global Function

Local Storage:

Find Details Here: Local Storage

Kitchen Sink Example Here: Local Storage

Implementing the GamePlay: Let's dive into the fun part - the gameplay!

Check Out The GamePlay Screen: GamePlay

Initializing the Game: As we start the game, our gameplay code will kick off with an onLoad event that triggers the "initializeGame()" function. This function sets up the game with all the initial states, including variables for status, tiles, images, matched tiles, chances left, and more.

View:
  onLoad:
    executeCode:
      body: |
        //@code
        initializeGame();

Javascript:

Find Details Here: Javascript

Execute Code:

Find Details Here: executeCode

Kitchen Sink Example Here: executeCode

Game Layout and Styles: We'll make sure to add a background image and use safe area settings to make the game look stunning on any device. Our gameplay screen will be carefully designed with a stack layout, allowing for layered elements. It's the perfect way to create an engaging and visually appealing gaming experience!

  body:
    Stack:
      children:
        - Conditional:
            conditions:
              - if: ${ensemble.storage.status == "WON"}   
                Lottie:
                  source: ${env.animation_lottie}
                  styles:
                    width: ${device.width}
        - Column:
            styles:
              padding: 24
              gap: 16
              crossAxis: center
            children:
              - Row:
                  children:
                  - Icon:
                      icon: arrow_back
                      styles: 
                        size: 30
                        color: pink

Find Details Here: Stack

Kitchen Sink Example Here: Stack

Conditional Rendering: The gameplay screen will adapt based on the game's status. When you win, we'll celebrate with a cheerful animation using the Lottie component. And when things don't go as planned, we'll have messages like "YAY, YOU WON!" or "OOPS! YOU LOST."

        - Conditional:
            conditions:
              - if: ${ensemble.storage.status == "WON"}   
                Lottie:
                  source: ${env.animation_lottie}
                  styles:
                    width: ${device.width}

Find Details Here: Conditional

Kitchen Sink Example Here: Conditional

Header Section: We won't forget the essentials - the header section! It'll have an interactive arrow back icon, allowing you to navigate back to the home screen whenever you want.

Find Details Here: Icon

Kitchen Sink Example Here: Icon

Game Status: We'll keep you informed about your progress with a friendly game status display! Depending on how you're doing, we'll show you different elements. If you're just starting or taking another chance, we'll let you know how many chances you have left. And when you win, expect a victory message to celebrate! If things don't go as planned, don't worry, we'll encourage you to give it another go!

              - Text:
                  text: Tap to match 2 tiles each time until there are none left to win the game!
                  styles:
                    padding: 10
                    textAlign: center 
                    textStyle:
                      fontSize: 15
              - Conditional:
                  conditions:
                    - if: ${ensemble.storage.status == "null"}
                      Column:
                        styles:
                          crossAxis: center
                          gap: 4
                        children:
                          - Text:
                              styles: 
                                padding: 20 30
                                backgroundColor: 0x11000000
                                textStyle:
                                  fontSize: 35
                                  color: pink
                              text: ${ensemble.storage.numChancesLeft}
                          - Text:
                              styles:
                                textStyle:
                                  fontSize: 15 
                              text: Chances left
                    - elseif: ${ensemble.storage.status == "WON"}
                      Text:
                        text: YAY, YOU WON!!
                        styles:
                          textStyle:
                            color: pink
                            fontSize: 30
                          padding: 5
                          textAlign: center

                    - else: ${ensemble.storage.status == "LOST"}
                      Text:
                        text: OOPS! YOU LOST.
                        styles:
                          textStyle:
                            color: pink
                            fontSize: 30
                          padding: 5
                          textAlign: center

Game Tiles: The heart of the game! We'll render the game tiles in a special way using a nested Column within a FittedRow component. When you tap a tile, a series of functions will be executed to make the magic happen - flipping, matching, and more!

              - Column:
                  styles:
                    margin: 24 0
                  children:
                    - FittedRow:
                        children:
                          - Tile:
                              inputs:
                                position: 0
                          - Tile:
                              inputs:
                                position: 1
                          - Tile:
                              inputs:
                                position: 2
                          - Tile:
                              inputs:
                                position: 3

FittedRow:

Find Details Here: FittedRow

Kitchen Sink Example Here: FittedRow

Flipping Tiles: Our "flipTileOn(position)" function will bring the tiles to life by updating the ensemble.storage.images array with the image URL for the corresponding tile. You'll see those tiles flip like they're dancing!

  function flipTileOn(position) {

    var imageIndex = ensemble.storage.tiles[position][1];
    //console.log('imageIndex :' + imageIndex);
    
    var imageUrl = ensemble.storage.icons[imageIndex];
    //console.log('imageUrl :' + imageUrl);

    var images = ensemble.storage.images
    images[position]= imageUrl;
    ensemble.storage.images = images;

    //console.log('images array :' + ensemble.storage.images);
  }

Handling Tile Taps: Tap, tap, tap - and the fun begins! When you tap a tile, it'll trigger a sequence of functions. We'll check if it's your turn and flip the tile if it is. Then, the game state will be updated, all thanks to our "updateGameState(prevTilePosition, position)" function.

Tile:
  inputs:
    - position
  body:
    Column:
      onTap:
        executeCode:
          body: |
            //@code
              var status = ensemble.storage.status;
              if(status == "null") {
                var prevTilePosition = ensemble.storage.previousTilePosition;
                var inTimer = ensemble.storage.inTimer;
                //console.log('inTimer: ' + inTimer);
                if(inTimer == "false"){
                  flipTileOn(position);
                }
                
                updateGameState(prevTilePosition, position);
              }

Tile Matching: We've added a timer to keep things fair and fun. After tapping a tile, the timer will ensure everything goes smoothly, and our "whenATileIsClicked(prevTilePosition, position)" function will check if the previous and current tile positions match. Matching tiles will appear, or the game status gets updated to keep you guessing!

          onComplete:
            startTimer:
              id: tileClickedTimer
              options:
                startAfter: 1
              onTimer:
                executeCode:
                  body: |
                    //@code
                    var prevTilePosition = ensemble.storage.previousTilePosition;
                    if(prevTilePosition != position){
                      whenATileIsClicked(prevTilePosition, position);
                    }

startTimer:

Find Details Here: startTimer

Kitchen Sink Example Here: startTimer

Resetting the Game Turn: Our "resetTurn()" function will reset the game turn. We'll set the withinAturn variable to "false" and clear the previousTilePosition variable so you can continue playing with a fresh start!

  function resetTurn(){
          
    ensemble.storage.withinAturn = "false";
    //console.log('Turned OFF inTurn');
    ensemble.storage.previousTilePosition = none;
    var inTurn = ensemble.storage.withinAturn;
    //console.log('In Turn :' + inTurn);
  }

If you are interested in creating a game yourself check out the links below!

Create An Ensemble Account

Join Us On Discord

Review Our Mind Tiles Code

It's time for you to jump into the world of Mind Tiles and enjoy the memory matching fun! Happy playing!