A couple of months ago I wrote two posts about RaspberryPi and Python (Docker and Oh My ZSH). At the same time I bought Sense HAT to play a little bit with it. The first thing, besides modification to my RasPi case, was coding tutorial which took me trough basic concepts of the hardware while I was creating classic Slug game (probably known under different name).
Once I’ve managed to complete it I decided to write another classic myself. Here you can find my “Sense Racing” tutorial.
This tutorial requires basic Python or generic programming knowledge
Getting started with Sense HAT
In any Sense HAT project (or tutorial) you woul need either:
- Raspberry Pi
- Sense HAT
- Preferably lates version of Raspbian
- Sense HAT for Python3
sudo apt-get install sense-hat
Every project needs to be started with either
sense_emu library import. In my code I’m doing it like that:
from sense_hat import SenseHat # from sense_emu import SenseHat
Where one of them needs to be always commented out and by default
sense_hat is the active one. It allows an easy switch between the production environment (actual Sense HAT) and the development environment (Sense emulator).
Before we will step into further implementation lets define how the game should look like. So here is our project definition.
- We will have a car (single pixel) driving on the stright track whith some obstacles appearing on the road as we move forward.
- Car will be able to move left and right in the bottom row, by pressing left and right keys.
- Hitting any obstacle will end game.
- Points are based on distance we make.
- We can accellerate speed for a short time by pressing up key.
- Base speed will increase beased on game time.
As everything on Sense HAT 8x8 display our graphic will be simplified to the maximum. Objects will be represented by different colour pixes, lets first define all colours that we need:
border_colourfor track borders that will create illusion of movement
car_colourso we know where we are
obstacle_colourand of course things we don’t want to hit
All colours are defined as (R,G,B) in range
0 - 255 here are mine:
blank = (0, 0, 0) border_colour = (0, 0, 200) car_colour = (100, 200, 0) obstacle_colour = (100, 0, 0)
Race is completely different concept to Slug, our car will be moving by not moving at all. Actualy background has to move downwards. In such case we have to “remember” state of each point on screen and move it one row down and then create new row of track at the top. As shown on the image below, in the next step first row is becoming second, second is becoming third and so one. Only the car stays always at the bottom.
In order to achieve that we have to always redraw whole screen (like in classic CRT screen), so we have to create a matrix which will keep value of each pixel and at the beginning we will fill it with our background colour. As well as we have to define
distance and startup
track = [[blank for x in range(8)] for y in range(8)] distance = 0 sense = SenseHat()
Now any movement will be achieved by simple operations on
It’s time to create actual drawing function, as an argument we will take our
def draw(matrix): matrix.reverse() flat_list = [item for sublist in matrix for item in sublist] sense.set_pixels(flat_list)
To refresh state of pixels we will use built in
sense.set_pixels() which argument is a vector of rows from one the eight put one ofter another. So we have to convert our
8x8 matrix into
64 elements vector:
flat_list = [item for sublist in matrix for item in sublist]
And what is most important here, as we want our car to move forward by actually moving background backwards we have to reverse the
As we already have a function which will draw a frame based on a given matrix of values. It’s time to generate some track:
def gen_track(): line = [blank for x in range(8)] if distance % 4 > 1: line = border_colour line = border_colour return line
This function is generating single line, which later on will be put ath the end (so after reverse at the beginning) of the
matrix. At the moment its just empty line generated in the same way as initial matrix
[blank for x in range(8)].
And then it generates track borders in two of four cycles
distance % 4 > 1 this can be change later if you desire different pattern of track border.
Filnally we have to use all created functions:
if __name__ == '__main__': while True: track.append(gen_track()) draw(track[distance:distance + 8]) distance += 1 sleep(0.5)
Game needs to happen in the infinit loop, eveytime frame wi will append track with a new line generated by
gen_trac() and we will draw last 8 rows of it. Then we have to increment
distance which tells program how far we moved on the track and to slow down cycles a little bit we will use
sleep(0.5) the actual value can be adjusted to your needs. Dont forget to add import:
from time import sleep
If you run this and you have everything setup corectly you shoudl see in your emulator track moving forward. Now you can try commenting out
matrix.reverse() reverse line and see the effect.
This will be contiuned in the next post.