Building a game in Vue js part 1 of 2

In this tutorial we show how to build a simple game with Vue.js.

Let’s walk through how to build a simple game with Vue.js. Perhaps you’ve heard of a game called: Simon Says? Children play it and once upon a time there was a physical game built in the same vein called: Simon. If you want to skip the reading and look at the finished app, follow this link.

While a seemingly simple concept building this game brought some unexpected challenges which I hope to walk through below. Although Vue js makes the game foundation easier to build upon, the logic itself relies on our knowledge of javascript. I know I learned a lot by doing this exercise and I hope you will, too!


Below are some concepts we are going to be using in our game. Take some time to familiarize yourself with these as some of the code may be confusing if you are not.

Vue js and some of the concepts we are going to utilize
Computed Properties
Event Handlers 
HTML/CSS Bindings
LifeCycle Hooks

General programming and some of the concepts we are going to utilize:
Recursion
Timeouts
Object Iteration
Accessing Object Properties
Bitwise Operators

OK! Once we are familiar with those concepts lets apply them to our game. When I started thinking about how to approach this it was easier for me to break it down into small steps. These are what I came up with:

  1. render four squares on the DOM
  2. add a click event to the squares
  3. programmatically add/remove highlighted CSS styling
  4. return random object element to apply highlighting
  5. introduce concept of a level/round
  6. work with the click events captured in step 2
  7. make game loop based on the level/round we are on
  8. start game / lose game

Some of these steps are more difficult than others, and you don’t necessarily have to think in these terms. These are what worked for me to help me think through it. You should do whatever helps you. As long as the end result is the same it doesn’t matter how we got there. It should be noted that I did not follow the original game to a T. In the original, you continually build upon the same sequence combination, in this game I am generating a random sequence each time. Also in this tutorial I am assuming you are familiar with the Vue js CLI.

Lets get started!

Step 1:
Lets get the project set up and throw on some CSS to make our squares appear. We should be seeing something like this. The commit can be found here.

Step 2:
 This is where we are going to leverage some of Vue’s functionality. Sometimes it helps me to see some functionality on the screen. So lets add a click event handler to our squares and highlight the one we clicked. The first thing we need to do is add more CSS classes to apply to the square when it is clicked. They can be any hex code you like but it helps if it’s the same color so it has the appearance of being highlighted. Let’s look into the code that will help us complete this step. The first thing is to add a click event. This is pretty straight forward and call be lifted directly from the documentation.

<div class="red" v-bind:class="{red_active" active.red === true}" v-on:click="handleClick($event)></div> 
Let’s look more closely at this code: v-bind:class states that we have a CSS class called red_active and anytime an object, in this case active, with the key red is true we are going to bind this class to the div. The other thing going on in this div is the click event. Basically all this is saying is that anytime this div is clicked, we are going to call the method handleClick and pass it a special $event variable. We can try this out ourselves with very little code.

<template>
<div id="game">
    <div class="red" v-on:click= "handleClick($event)"></div>
<div class="blue"></div>
<div class="yellow"></div>
<div class="green"></div>
</div>
</template>
...
export default {
name: 'SimonSays',
data () {
return {
}
},
computed: {
},
methods: {
handleClick(target) {
console.log(target)
}
}
}
...

Pretty easy, huh? Now we can start to think about what we need for the game itself. Let’s dive deeper into what this method needs to do. In the v-bind example I mentioned an object active. This object needs to hold the color of the square as the key and a boolean as the value. If we map our CSS class names to the object key, we can sequentially search through our active object and perform an action when we find a match. Thinking in non-code terms, what needs to happen is this: we have access to properties through our $event variable, one of these properties is the CSS class name which in our case is the color of the square. We loop through our active object and match the CSS class name with the color of the div. When we find a match we update the property in the active object to be true. Let’s look at what this code might look like:

handleClick(target) {      
const self = this

Object.keys(self.active).forEach(key => {
if(target.currentTarget.className === key) {
self.active[key] = true
}
})
}

So far so good. Even with this small amount of code we can see the game coming together! Here is the commit if you want to take a look.

Step 3:
Now that we can add highlighting via click events let’s create a way to generate the highlighting sequence programmatically. This is where the concept of a game loop is starting to come into play. Although we’re not ready to implement that functionality yet, it’s good to start thinking about how we can solve that problem. We can leverage the same concept in step two, albeit with some enhancements, to make it work for us. Adding and removing the CSS classes for each div gets tricky because you’re looping through an object some specified amount of times, and you want to create a delay effect. Meaning that I want the highlighted square to remain highlighted for a discernible amount of time before moving onto the next element. With the help of this extremely helpful post we can do just that.

Although we can do this in one method, it’s a large chunk of functionality so let’s break it into smaller units. One method is going to be in charge of looping, one method can be in charge of applying the highlighting, and one method can be in charge of removing the highlighting. We are also going to need a way to call the looping method once the component is created. To break things down even further let’s focus on toggling the red square 10 times. To make this happen I also declared another object called, hexCodes. This is a mapping of colors to their hex codes. We will utilize this for our sequential search below. Let’s look at the code.

//lifecycle hook
....
created() {
const self = this
let i = 10
self.startGame()
},
....
//methods
startGame(i) {
const self = this
  setTimeout(function() {
let redSquareHexCode = self.hexCodes.red
self.setElementToTrue(redSquareHexCode)
if (--i){
self.startGame(i--)
}
}, 3000)
},
setElementToTrue(randomHex) {      
const self = this
Object.entries(self.hexCodes).forEach(key => {
if (key[1] == randomHex) {
self.active[key[0]] = true
self.toggleToFalse()
}
})
},
toggleToFalse(key) {
const self = this
  setTimeout(function() {
Object.entries(self.active).forEach(key => {
self.active[key[0]] = false
})
}, 1000)
},

OK. There’s a lot going on here, so let’s talk about it. On a high level all this is doing is grabbing the red square toggling it to be highlighted, and then toggling it off to go back to it’s original color. 
When the component is created in the Vue lifecycle, it calls the method startGame(). Every 3 seconds start game recursively calls itself and takes the red square element in our active object, and passes it to setElementToTrue(). This method sequentially searches through the hexCodes object, although we are looping through objects and accessing their properties, at the end of the day we are simply doing a string compare. When we find a matching string, we access that property in our active object and set it’s boolean value to true. This will trigger our v-bind and create the desired highlighted effect. Then we call toggleToFalse() which loops through our active object again and sets all the elements back to false after a one second delay. I am intentionally not going into detail in regards to the setTimeout functionality due to the linked post above which frankly does a much better job at explaining it than I could do. So if you didn’t read it do yourself a huge favor and do so. You’ll learn a ton, I know I did. 
Wow! That was a big step! But take a look at the functionality we created. Here is the commit if you’re interested.

We although we are less than half way through our steps, I would say that we have more than 70% of the functionality created for the game. Let’s move on to step 4.

Step 4:

In this step we are simply going to randomly pick an element from our hexCodes object and pass it to our setElementToTrue method. This is in lieu of always passing it the color red. This can be done in a very straight forward way since we know that we are always going to have 4 elements in our object, but what happens if we do now know the length? If you’d like to read more about this classic computer science question here is a great post. There are a few ways to do this but since we know the length I will give that example as well as an example if we didn’t know that information.

//if we didn't know the length
returnRandomHexCode() {
const self = this
let keys = Object.keys(self.hexCodes)
return self.hexCodes[keys[ keys.length * Math.random() << 0]]
},
//if we did know the length
returnRandomHexCode() {
const self = this

return Math.floor(Math.random() * 3)
}

In the first example which uses a bitwise operator we are generating a random number in between 0 and 1 and multiplying it by a factor of the list length. << 0 truncates the list to an integer because that operator only operates only on 32-bit integers. This code was first seen in this stack overflow post. The second example chooses a random element between 0 and 3 and rounds it down to the nearest whole number. In this case it will randomly return 0, 1 ,2, 3 which is how many elements are in our list. Now that we have this code in place we can replace our line that always give us our red element with one of these two methods. Here is what the updated code looks like:

...
startGame() {
const self = this
setTimeout(function() {
let randomHex = self.returnRandomHexCode()
self.setElementToTrue(randomHex)
if (--self.level) {
self.startGame()
}
}, 3000)
},
.....
returnRandomHexCode() {      
const self = this
let keys = Object.keys(self.hexCodes)
return self.hexCodes[keys[ keys.length * Math.random() << 0]] },
...

Here is the commit if you’re following along.

OK. This post is getting pretty long so I think I’m going to cut this one here and post the remaining in another post.