Arcade shooter game with Python, Raspberry Pi and Sense HAT

Albert Schweitzer
5 min readJun 15, 2017

--

One of the cool things about the Raspberry Pi + Sense HAT is that it comes with a joystick and LED matrix, offering an easy to use kit for simple games like snake, pong and arcade shooters. This project will demonstrate how to use Object-oriented programming, handle user input and track state changes with a fun, hands-on approach.

Requirements:

  • Raspberry Pi and Sense HAT (ours were donated to Game Bahrain by the awesome people at Hackster.io)
  • A basic knowledge of Python and Object-oriented programming

Set up

First we’ll set up the environment and import the libraries we’ll need for our project. We also want to track the player’s score, time and the non-player objects:

Next, we’ll start building our Player class. The __init__() function is a constructor that runs whenever we create a new object. Our constructor takes x and y variables, then turns on the corresponding pixel in the LED matrix. Object methods always take the argument self, which refers to the object calling it.

Reading User Input

Now that we’ve created the player we want to use the joystick to move it around the screen. The documentation on www.pythonhosted.org has an example of how the joystick works. Let’s create a while loop at the bottom of our program that calls the get_events() function to check for movement and see what that looks like:

Your output should look something like this:

The joystick output is a string indicating the direction it was pushed.

The joystick returns a string with the direction it was pushed. We can use this to create create a global function to handle this logic rather than replicating it for each object. Before we do that, let’s look at how the Sense HAT defines the x and y LED grid on the shield:

The grid can feel a bit unintuitive at first because the y axis increases as the player moves down. We use the Sense HAT’s set_pixel function to position objects by turning pixels on and off. In the above image, the blue pixel would be turned on with sense.set_pixel(0,2,blue) and the red with sense.set_pixel(7,4,red).

Moving Around

Because all of our objects will move in a similar fashion, we only need one function to process an x, y and direction into new x, y coordinates. Let’s call this getCoordinates(), place it above the while loop:

Now let’s add a move() function to our Player class. This function takes a direction from the joystick and uses getCoordinates() to determine the new position of our player. The function then checks these new coordinates to make sure the new x and y are within the bounds of the LED matrix, otherwise if we tried calling sense.set_pixel() we’d get an error that would crash our program.

Now that we have an idea of how to read from the joystick, let’s create an instance of our Player object and move it around the screen a bit. Edit the while loop to include code below:

Cool! We have given our Player class the ability to move around the screen without crashing whenever the player is about to go out of bounds. Now we can add a fire() method at the bottom of our Player class. The function creates a new Bullet object and adds it to our bullets list so we can keep track of it.

Now let’s make a Bullet class below the Player class and methods. The constructor will take an x and y coordinate from the player object, but will place the bullet one pixel away in the direction it was fired.

Now we can update our while True: loop to handle the joystick being pressed:

Now our player is successfully firing a bullet, but how can we get it to move? Let’s create a global moveObjects() function to handle the logic of moving our bullets around the game. Place it after getCoordinates:

In this function we use a for-in loop to iterate through the bullets List. The function checks that bullet is still in bounds of the matrix, and if not it is removed from the game and the List. Call this function just below where you handle the player input. This is a pretty good time to run your program and make sure everything is working!

Now we’re ready to create our Baddie class. These objects will move accross the screen and will end the game whenever they catch the player. Whenever the object hits the perimeter, the getDirection() function will randomly give it a new direction to go. Add it below the Bullet class:

Now we can add logic to our while loop that updates the timer once per tick and creates a new Baddie object whenever the threshold is met. We’ll also add a line of code to make sure our player object is visible in case it has been drawn over by a stray bullet:

Let’s add to our moveObjects() function the include logic for our baddies:

The first thing we do is get new coordinates for our Baddie object. If the new coordinates are valid, we use the Sense HAT’s get_pixel() to check for the color at the bullet’s new location. If the color matches the player’s color, we set the global alive variable to False in order to end the game. If the color matches a bullet, we take the baddie out of the game and update the global score variable. If neither are true the baddie simply moves to its new position. If the new coordinates are out of bounds, the baddie calls the getDirection() function to move elsewhere.

Now we can update our while True: loop to make the game progressively harder and end the game if the player is caught by a baddie:

Now we can show a message with the score for when the player is taken out of the game. Outside the while loop use the Sense HAT’s show_message() function:

Check out the final project on GitHub!

My high score is 50!

--

--

Albert Schweitzer

Software Engineer and fractional CTO specializing in healthcare, education and emerging tech. Contact me to talk about tech strategy and MVPs www.thinkbuild.it