microbit Games-Controlling Movement on the LED Matrix
2022-03-10 | By Kitronik Maker
License: See Original Project
Courtesy of Kitronik
Guide by Kitronik Maker
Do you have an urge to write some microbit games but don't know how to start, maybe we can help? Learning how to code some basic gaming functions could be all you need to overcome coders block. Today we are going to take it back to basics and learn a couple of key concepts. Processing user input and also taking control of the LED matrix, both required knowledge if you want to create engaging games.
Although we referred to Today's topics as basics, they can become quite tricky if your game is quite complex. We will illustrate three ways of processing user input and also three ways of moving a LED around the matrix.
You Will Need:
- A computer/laptop with a USB port and internet access (or MakeCode Desktop App)
- 1 x BBC micro:bit
- Optional: :GAME Controller
- A micro USB cable
- Optional: An input device such as a thumbslide joystick, or thumb joystick.
You Will Learn:
- Processing user input on the microbit
- How to process user input from an external device
- Controlling movement on the LED matrix
- That there is always more than one way to get the desired result
microbit Games - Controlling Movement on the LED Matrix:
We've got four code examples to go through, starting with the most difficult/unwieldy first. The first two make use of the Input buttons of the microbit, the third utilises an external analogue device and the fourth makes use of the :GAME Controller for BBC micro:bit. All of the examples are coded using the Microsoft MakeCode editor and we chose to use blocks. The four sections are;
• 1 - Using the 'LED blocks' in the MakeCode editor to light up an LED, then move it with button presses. Jump
• 2 - Use the MakeCode 'Game blocks' to create a sprite on the screen, then move it with button presses. Jump
• 3 - Use the 'Map block' to gather user input from a joystick via the microbit gpio pins. Jump
• 4 - Using a dedicated gaming platform such as the :GAME Controller. Jump
1 - Take the Scenic Route:
Disclaimer: Firstly, don't be put off by this method, there are easier and more efficient ones to follow!
What Does the Code Do:
The code accepts input from the user via the microbits A and B buttons and also when the microbit is shaken. The lit LED is given a starting position and the user input takes over from there. A moves the LED left, B moves the LED right, A+B moves the LED up and shake brings it to the bottom of the column. Additionally, there is code that ensures the lit LED can't disappear off the edge of the LED matrix.
How Does the Code Work:
There are five distinct chunks of code, four that handle each type of user input and one that sets the starting position for the LED. The code relies heavily on the use of variables, in this case, X-Pos and Y-Pos. The contents of the variables are updated by user input and the results are plotted to the screen in real time. Let's take a closer look.
The On Start Block:
The above image shows how the LED matrix is arranged in terms of x and y and also where our starting LED is plotted. In the variables menu, we create two variables; X-Pos and Y-Pos. We use these throughout the program to keep track of the LEDs position. In this block, we just need to input a starting point and then plot it to screen. The 'plot' block can be found in the LED menu and the 'set' blocks and the X-Pos/Y-Pos lozenges can be found in the 'Variables' menu. Now we have an LED lit up we need to figure out how to move it.
The on Button Press Input Blocks:
The code above allows for three different types of button press; A button pressed, B button pressed, and A and B pressed together. You will notice that the code for each is almost identical as they all move the LED one place; left, right, and up respectively. Each code block also has code to make sure the LED can't disappear off the edge of the display.
On Button A Pressed:
When the A button is pressed the variable X-Pos is changed by minus 1. If you refer to the grid further up, you will see that this will result in the X-Pos variable being updated with a number that will move it one space to the left. The code then clears the screen of its last location and replots it with the updated value now held in the X-Pos variable. The LED moves one space left.
On Button B Pressed:
When the B button is pressed the variable X-Pos is changed by plus 1. If you refer to the grid further up, you will see that this will result in the X-Pos variable being updated with a number that will move it one space to the right. The code then clears the screen of its last location and replots it with the updated value now held in the X-Pos variable. The LED moves one space right.
On Button A+B Pressed:
When the A and B buttons are pressed at the same time the variable Y-Pos is changed by minus 1. If you refer to the grid further up, you will see that this will result in the Y-Pos variable being updated with a number that will move it one space upwards. The code then clears the screen of its last location and replots it with the updated value now held in the Y-Pos variable. The LED moves one space up.
The Code that Keeps the LED On Screen:
Each of the button press options has code contained within an 'if' block (found in the logic menu). This ensures that the LED cannot go any further, in the current direction of movement, than the edge of the display. In the grid further up, you can see the values for the edge of the screen. In the case of the B button press; if the X-Pos value is greater than 4 it will be reset to 4 and replotted. No matter how many times you try to move further than the edge, the position will just be reset to the edge.
The On Shake Input Block:
This block is much more straightforward than the on button pressed blocks. When the microbit is shaken, the Y-Pos variable is overwritten with a value that will move the LED down to the bottom. The screen is cleared of the last known location and replotted with the new value of Y-Pos. Because we have updated the Y-Pos variable with an absolute value we don't have to worry about code to stop the LED dropping off the screen.
Grab the Code:
Microsoft MakeCode | Terms of Use | Privacy | Download
input.onButtonPressed(Button.A, function () {
XPos += -1
basic.clearScreen()
led.plot(XPos, YPos)
if (XPos < 0) {
XPos = 0
basic.clearScreen()
led.plot(XPos, YPos)
}
})
input.onButtonPressed(Button.AB, function () {
YPos += -1
basic.clearScreen()
led.plot(XPos, YPos)
if (YPos < 0) {
YPos = 0
basic.clearScreen()
led.plot(XPos, YPos)
}
})
input.onButtonPressed(Button.B, function () {
XPos += 1
basic.clearScreen()
led.plot(XPos, YPos)
if (XPos > 4) {
XPos = 4
basic.clearScreen()
led.plot(XPos, YPos)
}
})
input.onGesture(Gesture.Shake, function () {
YPos = 4
basic.clearScreen()
led.plot(XPos, YPos)
})
let YPos = 0
let XPos = 0
XPos = 2
YPos = 4
led.plot(XPos, YPos)
2 - Obey Your Thirst for Simplicity with Sprites:
What Does the Code Do:
The code accepts input from the user via the microbits A and B buttons and also when the microbit is shaken. The lit Sprite is given a starting position and the user input takes over from there. A moves the Sprite left, B moves the Sprite right, A+B moves the Sprite up and shake brings it to the bottom of the column. Additionally, there is code that ensures the Sprite can't disappear off the edge of the LED matrix.
A Word About Sprites:
Many of our Kitronik microbit boards can be coded using custom blocks that we've added to the MakeCode editor. These blocks simplify the job of coding by containing a number of functions within a single block. Sprites are much the same, as each Sprite block hides a number of coded instructions within it. This means you can do some pretty complicated things with relatively few blocks. This is great when you are starting out as it is less likely you will convince yourself that it's too difficult to learn. A host of Variables can look quite scary to the novice, Sprite commands much less so.
How Does the Code Work:
There are five distinct chunks of code, four that handle each type of user input and one that sets the starting position for the Sprite. The code is simplified greatly by the use of Sprites. Essentially it works in the same way as the more complicated version above but requires much fewer blocks. Each button press moves the Sprite in the desired direction and the 'if on edge bounce' block ensures the sprite stays on the screen. Let's have a closer look.
The On Start Block:
The above image shows how the LED matrix is arranged in terms of x and y and also where our starting Sprite is plotted. In the Game menu, we get the create sprite block and place it into a 'set variable' block from the variables menu. In this block, we just need to input a starting point. Now we have a Sprite lit up we need to figure out how to move it.
The on Button press Input Blocks:
The code above allows for three different types of button press; A button pressed, B button pressed, and A and B pressed together. You will notice that the code for each is almost identical as they all move the Sprite one place; left, right, and up respectively. Each code block also has code to make sure the LED can't disappear off the edge of the display. As you can see, this code is much less complicated than in the first example. One block that both changes the x/y value and replots the sprite and another block that stops the Sprite from disappearing off the display.
On Button A Pressed:
When the A button is pressed the Sprites x value is changed by minus 1. If you refer to the grid further up, you will see that this will result in Sprites x value being updated with a number that will move it one space to the left.
On Button B Pressed:
When the B button is pressed the Sprites x value is changed by plus 1. If you refer to the grid further up, you will see that this will result in Sprites x value being updated with a number that will move it one space to the right.
On Button A+B Pressed:
When the A and B buttons are pressed at the same time the Sprites y value is changed by minus 1. If you refer to the grid further up, you will see that this will result in the Sprites y value being updated with a number that will move it one space upwards.
The Code that Keeps the LED On Screen:
Each of the button press options has a code block for 'if on edge bounce'. This ensures that the Sprite cannot go any further, in the direction of movement, than the edge of the display. No matter how many times you press the button, the Sprite cannot move any further than the edge of the screen.
The On Shake Input Block:
When the microbit is shaken, the Sprites x value is overwritten with a value that will move the LED down to the bottom of the column it is in. Regardless of where the Sprite is, the code will move it down to the bottom. Additionally, the if on edge block ensures it stays on the screen.
Grab the Code:
Microsoft MakeCode | Terms of Use | Privacy | Download
input.onButtonPressed(Button.A, function () {
Sprite.change(LedSpriteProperty.X, -1)
Sprite.ifOnEdgeBounce()
})
input.onButtonPressed(Button.AB, function () {
Sprite.change(LedSpriteProperty.Y, -1)
Sprite.ifOnEdgeBounce()
})
input.onButtonPressed(Button.B, function () {
Sprite.change(LedSpriteProperty.X, 1)
Sprite.ifOnEdgeBounce()
})
input.onGesture(Gesture.Shake, function () {
Sprite.change(LedSpriteProperty.Y, 4)
Sprite.ifOnEdgeBounce()
})
let Sprite: game.LedSprite = null
Sprite = game.createSprite(2, 4)
3 - Let's Take It Outside (of the micro:bit with a joystick):
The animation of the simulation is a little different for this one. Although there is no animation of a joystick, we can manually change the value on the pins in use. Pins 0 and 2 are reading x and y values from the joystick respectively. You can see this in action above, as I pick a value for these pins the LED moves.
The Thumbslide Joystick:
The X & Y axis pads on the underside of the joystick output an analog voltage, you can code the microbit to monitor and read these voltages and translate that into an action. In this example we used the Microsoft Block Editor and made use of the 'map' block to read the output voltages from the X & Y Axis and convert them into a value from 0 to 4 so that the position of the joystick can be tracked using the LED matrix on the micro bit. An edge connector and breadboard is a great way of prototyping this setup. You can expect a range of about 128 to 775 on each axis. You will need to experiment, as the range may vary from joystick to joystick. Note: For wiring this part; if you look at the device from the bottom, the pin out goes:
We wired the X axis output on the Joystick to P0 on the microbit and the Y axis output to P2 on the microbit. If you choose to use different pins you will need to adjust the code accordingly.
What Does the Code Do:
The code accepts user input via Pins 0 and 2, these pins are connected to our joystick. Pin 0 is reading movement in the x axis and Pin 2 the y axis. We then use the map block, found in the Pins menu, to convert the pin readings to values that can be stored in our x and y variables. The map block collects readings between two values that we specify. We checked the specs of the joystick as a starting point and tweaked them with a bit of trial and error. Once the microbit is interpreting these values adequately we can then plot the x and y values to the screen. The LEDs position will update in real time. So, any change in the joystick position will instantly be reflected in the LED matrix. All of the 'if' statements contain code to stop the LED disappearing off the edge of the screen in all four directions. Let's take a closer look.
The On start Block:
In the Variables menu we create two variables, one for x and one for y. The on start block only contains the code to set the contents of the variables to zero. As both variables will receive real time updates from the map function, explained below, they will be immediately updated with the joysticks position. Unless you are touching the joystick the LED should show up in the middle of the LED matrix if the map block has the correct values entered into it.
The Map Blocks:
When the joystick is moved this creates a change in voltage on the microbits GPIO pins. In this case the P0 and P2 pins. The mapping block, found in the pins menu, reads the changes within a range that we set. It then converts them to meaningful numbers that are stored within the respective variables. As both LED matrix axis go from 0 to 4, we also input this into the map blocks. The map blocks for each axis have read the voltage, converted it to a number between 0 and 4 and stored it in the respective variable. You can expect a range of about 128 to 775 on each axis. It will take a little experimentation, as the range may vary from joystick to joystick. You can see in the image above the values we determined through trial and error; 175 to 750 for both.
Plotting the LED On the Matrix:
At the foot of the code in the forever block we use the same method used in the very first example. We clear the screen of the last position and use the plot led block from the led menu to place the LED using the current x and y values. This is done in real time and any changes will be immediately reflected on the LED matrix.
Edge Detection:
Each of the 4 edges of the LED matrix has an 'if' block associated with it. The values represent the x and y axis of the microbits LED matrix. We have highlighted this on an image of a microbit in examples 1 and 2 above. If the LED is moved beyond the limits of the matrix, there is an 'if' statement that sets it back to the edge. We use the 'set variable to' block ensure that the variable holds this corrected position.
Grab the Code:
Microsoft MakeCode | Terms of Use | Privacy | Download
let x = 0
let y = 0
basic.forever(function () {
x = pins.map(
pins.analogReadPin(AnalogPin.P0),
175,
750,
0,
4
)
y = pins.map(
pins.analogReadPin(AnalogPin.P2),
175,
750,
0,
4
)
if (x > 4) {
x = 4
}
if (x < 0) {
x = 0
}
if (y > 4) {
y = 4
}
if (y < 0) {
y = 0
}
basic.clearScreen()
led.plot(x, y)
})
4 - Let's Take It Outside 2 (This time it's personal, to Kitronik):
For our final example, we turn to our very own :GAME Controller for the BBC micro:bit. It not only offers a more comfortable gaming experience, but it also has 6 programmable buttons. The buttons can be coded easily using our custom MakeCode blocks.
To add them to your menu, click on the cog icon in the top right of the editor, then select Extensions. In the search bar type Kitronik and then press enter. Scroll to and select the Kitronik-game-controller tile and it will be added to your menu. For this example, we will be using our custom blocks in conjunction with Sprite blocks found in the Game menu.
What Does the Code Do:
The code accepts user input via pins; 12, 13, 15 and 16. These are the pins that relate to the codable buttons on the :GAME controller that we've chosen to use. Once a button press occurs it moves the Sprite either, left, right, up, or down. There is also code that ensures that the Sprite can't disappear off the screen. Let's take a closer look.
The On Start Block:
The above image shows how the LED matrix is arranged in terms of x and y and also where our starting Sprite is plotted. In the Game menu, we get the create sprite block and place it into a 'set variable' block from the variables menu. In this block, we just need to input a starting point. Now we have a Sprite lit up we need to figure out how to move it.
The on button joypad/fire button press blocks:
The above four blocks represent the four possible directions of movement, left, right, up, and down. On the :GAME Controller we utilised Joypad right and Left buttons and both fire 1 and 2 for up and down.
on button Joypad Left press:
When the left joypad button is pressed the Sprites position on the x axis changes by minus one. If you refer to the grid you will see that this will move the Sprite one place left on the LED matrix.
on button Joypad Right press:
When the right joypad button is pressed the Sprites position on the x axis changes by plus one. If you refer to the grid you will see that this will move the Sprite one place Right on the LED matrix.
on button Fire 1 press:
When fire 1 is pressed the Sprites position on the y axis changes by minus one. If you refer to the grid you will see that this will move the Sprite one place Up on the LED matrix.
on button Fire 2 press:
When fire 2 is pressed the Sprites position on the y axis changes by plus one. If you refer to the grid you will see that this will move the Sprite one place Down on the LED matrix.
The Code that Keeps the Sprite on the screen:
Each of the button press options has a code block for 'if on edge bounce'. This ensures that the Sprite cannot go any further, in the direction of movement, than the edge of the display. No matter how many times you press the button, the Sprite cannot move any further than the edge of the screen.
Grab the code:
Microsoft MakeCode | Terms of Use | Privacy | Download
Kitronik_Game_Controller.onButtonPress(Kitronik_Game_Controller.ControllerButtonPins.Right, Kitronik_Game_Controller.ControllerButtonEvents.Click, function () {
sprite.change(LedSpriteProperty.X, 1)
sprite.ifOnEdgeBounce()
})
Kitronik_Game_Controller.onButtonPress(Kitronik_Game_Controller.ControllerButtonPins.Fire2, Kitronik_Game_Controller.ControllerButtonEvents.Click, function () {
sprite.change(LedSpriteProperty.Y, 1)
sprite.ifOnEdgeBounce()
})
Kitronik_Game_Controller.onButtonPress(Kitronik_Game_Controller.ControllerButtonPins.Left, Kitronik_Game_Controller.ControllerButtonEvents.Click, function () {
sprite.change(LedSpriteProperty.X, -1)
sprite.ifOnEdgeBounce()
})
Kitronik_Game_Controller.onButtonPress(Kitronik_Game_Controller.ControllerButtonPins.Fire1, Kitronik_Game_Controller.ControllerButtonEvents.Click, function () {
sprite.change(LedSpriteProperty.Y, -1)
sprite.ifOnEdgeBounce()
})
let sprite: game.LedSprite = null
sprite = game.createSprite(2, 4)
That's all folks, for now...
We hope you got something useful from this microbit games writing resource. We intend to build on this with further, and possibly shorter, resources in the future that cover other aspects of writing games for the microbit. Please feel to comment below with any requests as to which topics you would like us to cover.
©Kitronik Ltd – You may print this page & link to it but must not copy the page or part thereof without Kitronik's prior written consent.
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum