Simon was a game that anyone who grew up in the 80s will remember well. It has a simple premise: a pattern is shown and the user tries to repeat the pattern. The original game had coloured buttons which you had to press.
A work colleague (Gary) came up with the idea for this project. We were looking for ways to showcase the gesture sensing capabilities of the SL06 and he suggested Simon. It turns out that a gesture based version of the game is quite fun. You could download the pre-compiled UF2 file and just play it, or work through the story below to see how it was programmed.
Screens:A good way to start designing a game is to think about are the screens / views that will be needed. I was quite surprised just how many screens I had to build:
- A new game screen
- Screens for all four of the arrows
- A screen during the process - while the user is entering values
- A screen when a round has been completed
- A screen when the target has been met / the game is won
- A screen when the user gets it wrong
In addition, as I optimised the code I found I needed to display a few other bits too:
- A randomising screen (more on that later)
- A countdown. This to warn the user about a transition of the screen.
- A sequence of screens showing the target pattern
Some of the screens are shown below:
In the code each screen is defined in a function, and the following conventions are used:
- For the Arrows the functions are called "DRAW_DIRECTION", e.g. drawUp, drawDown.
- For all other functions that display a screen the name is "SHOW_SCREEN", e.g. showRoundPass, showWin.
Bear in mind that all screens have to be shown on a 64x128 screen.
Once the screens are built the bulk of the work is done - we just need to stitch them together!
Game FlowThe flow of the game is quite straightforward, and is shown in the image below:
Each game has a target: a set of moves that the user has to copy, and for each move there are four options (up, down, left and right).
We need to generate and store this target - we use an array that contains random numbers (0, 1, 2 and 3). This is created in the initialiseAnswerArray function, shown below:
In the initialiseAnswerArray function note the following:
- A parameter, numberOfMoves, is passed in. This number is the total number of moves the user will be required to repeat to win. It is parametised here to allow the game to get harder, so when someone beats the game by repeating 10 moves it can be increased to 12 moves for the next game (and so on).
- An array containing numberOfMoves values is created, and is filled with random numbers from 0 to 3.
FYI. By convention, throughout the game the following is used:
- 0 = down
- 1 = up
- 2 = left
- 3 = right
The key to the game is allowing the user to input a gesture, then checking whether the gesture is correct (is it the same gesture in the target array?).
This is achieved as shown:
When each gesture is recorded a value (0, 1, 2 or 3) is sent to the checkUserGesture function. This value is compared to the value in the target array that corresponds to the current guess, as shown below:
The if statement above compares the current gesture to the gesture that is in the target array. The parameter currentScore is the number of correct guesses the user has made so far. If the user gets it right currentScore is incremented by 1, if not its game over.
At the beginning of each round currentScore is set to zero. Then, as the user gets their gestures right, this value is increased by 1. There is a target per round - currentTarget - the number of moves required to complete the round. When the target for the round is met the target increases by 1, a new round is started and currentScore resets to zero. There is also a target per game - totalMoves - when currentScore equals totalMoves the user has won the game.
There is a lot more to the game than is shown here, but the core mechanics have been listed. Work through the code-base to see how the other bits fit into the workflow.
RandomisingComputers cannot 'do' random numbers. Some emulate randomness so well that you would never realise, but the numbers generated are not truly random. It is convenient to think of computers as having a fixed list of numbers that they use to generate random numbers from.
The problem I had to deal with was that when the hardware booted up the same sequence of move is ALWAYS generated. This was useful in testing, but no good for anyone wanting to play the game for fun.
To 'randomise' the game what we do is call the random function a random number of times, so that when the target is generated for a user it starts at a different location in the fixed list used to generate randoms. The randomise screen therefore just keeps calling the random function until the user makes a gesture. In this way it is very unlikely that users will see the same pattern every time they start the application.
It is very simple to connect xChips and build digital tools. I am the world's worst solderer and I just don't like instruments with cables everywhere, so XinaBox is perfect for me. You could build a different hardware device though: any microprocessor, OLED and gesture sensor will do. And there are a ton of different microprocessors that you can code from MakeCode, so you should be able to port the code quite easily.
The device I built looks like this (although more white / less blue - some filter on my phone camera I guess!):
The CS11 (which is the microprocessor) connects to the IP03 (which provides power and is used to program the CS11) using 2 connectors, as shown below:
The following video shows how to connect xChips:
Going furtherThe SL06 also recognises colours.
This game could be adapted, quite easily: instead of gestures the user would be required to show coloured flash-cards each time.
Alternately, you could try to port the game onto different platforms. The link below will take you to a version of the game that was developed for the BBC micro:bit.
Comments