
After completing today’s tutorial we will have finished a lot of loose ends in the space shooter. Every game has some kind of display or system to tell the player their current status, such as their health or strength, and some kind of reward system, displaying a score or even giving actual rewards for achieving some goal. These are all used as a way to give the player feedback about their gameplay.
Currently, what our game is lacking is a way to let the player monitor the current status of their ship.
The goal of this tutorial is to teach us how to create and display our current health, our lives, and the scoring system using Pygame.
THE CODE FOR THIS TUTORIAL CAN BE FOUND ON GITHUB.
Create the display area
The first thing we need to do is to specify an area on our screen where we want to put the player’s information display. Since the enemies are coming from the top of the screen, that means we often have to look there. I tried putting it on the bottom of the screen, but found it distracting as it would draw my eyes away from incoming enemies.
The first thing we need to do is to create a simple black rectangle and blit it to the top of the screen. In the main( ) function, add:
1 |
black_bar = pygame.Surface((WINDOWWIDTH, 35)) |
There are a few things that we will be ‘blitting’ to the screen and so to make this post easier to follow, I will show all of the code to draw objects to the screen at the end. The black bar we have added looks like this:

That looks a little contrasting against the background, so I also added a gray border around the black surface to make it look better.
1 |
pygame.draw.rect(DISPLAYSURF, GREY, (0, 0, WINDOWWIDTH, 35), 3) |
Shield
Our shield will act as our health and will also serve as another indicator that our health is low when it disappears. In the last tutorial we added the shield, and this time we are going to use it to create a shield display. Let’s create a function called shield_bar that we will display in the top left corner of the window.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
def shield_bar(surface, player_shield): '''display the graphic and track shield for the player''' if player_shield > 100: player_shield_color = GREEN player_shield = 100 elif player_shield > 75: player_shield_color = GREEN elif player_shield > 50: player_shield_color = YELLOW else: player_shield_color= RED pygame.draw.rect(surface, GREY, (5, 5, 104, 24), 3) pygame.draw.rect(surface, player_shield_color, (7, 7, player_shield, 20)) |
In line 1, the shield_bar takes two arguments, the surface window and player_shield, which is the shield attribute we create in the Player class. player_shield is the current value of the shield. Here we check and use this function to update the shield bar in our window. The first if statement in line 3 checks to make sure our shield value can’t go over 100. If player_shield is greater than 75 then the bar is green. If it’s greater than 50, then it’s yellow. And if we go less than 50, we start displaying a red shield bar.
We draw a grey rectangle first to make it visually look nicer in our display, and then let’s draw the color of our shield on top of that in line 14.

Player lives
Now that we a shield meter, we need a way that will allow us to create lives, keep track of how many we have, and to take away a life if our shield reaches zero. In some classic arcade games, the life display is simply a small copy of the spaceship. In the main( ) loop, where we load all the other images let’s use our player_img and rescale it.
1 2 |
life_player_image = pygame.transform.scale(player_img, (25, 25)) life_player_image.set_colorkey(BLACK) |
Next, we need a function that will place the lives in the upper right corner of our window.
1 2 3 4 5 6 7 |
def draw_lives(surface, x, y, lives, image): '''display ship's lives on the screen''' for i in range(lives): img_rect = image.get_rect() img_rect.x = x + 30 * i img_rect.y = y surface.blit(image, img_rect) |
The draw_lives function has five arguments: the display surface, the x and y coordinates to display the lives, the number of lives, and the life_player_image we just created. For the number of lives in total, which is 3, lines 4 – 7 handle the location of each image and blitting them to screen.
Losing a life
Before we can move onto creating the score for our game, there is something else we must take care of first. Now that we can display lives, how do we keep track of our shield and what happens when the shield reaches 0. Furthermore, if our shield does reach 0, we can’t just have our ship explode but still be hanging out on the screen after the explosion. We need to hide our ship and to re-spawn it after a couple seconds have passed by.
In the main game while loop, where we check for collisions between the player and enemy attacks or hits, we need to add three instances where our player will need to check and handle if their shield is 0. The first one is where our player is hit by an enemy bullet and our shield goes below 0.
1 2 3 4 5 6 7 8 9 10 11 12 |
# check if enemy bullet hit player player_hit_by_bullet = pygame.sprite.spritecollide(player, enemy_bullets, True) # if player is hit for hit in player_hit_by_bullet: player.shield -= 5 if player.shield <= 0: expl_ship = Explosion(player.rect.center, 'ship', explosion_anim) all_active_sprites.add(expl_ship) player.hide() player.lives -= 1 player.shield = 100 |
Rather than editing out the parts we have covered before, I want to show you what is going on. In line 2, we check if our player ship is hit by a enemy bullet. If it is, then we reduce the shield by 5 in line 5. Then in line 6, we check if player.shield is less than or equal to 0. If so, play the explosion, call the player.hide( ) function (explained soon), subtract 1 life, and reset player.shield to 100.
We also need to check for collisions between the asteroids and players, and between enemy ships and players. The logic and code is exactly the same for each part, so I have not included it here.
Your current screen should look like this:

My ship blew up! Now what?
Let’s take a quick look at the player.hide( ) function up above. What we want to do is make the player disappear if they are destroyed. The easiest way is to just move them offscreen for a few seconds and then move them back to the starting position.
1 2 3 4 5 6 7 8 |
class Player(pygame.sprite.Sprite): '''create Player class''' ###### OMITTED ###### # other player attributes self.shield = 100 self.lives = 3 self.hidden = False self.hide_timer = pygame.time.get_ticks() |
Here we set player.lives equal to 3, and also create a boolean object called self.hidden that will be False for now, but True if the player’s shield equals 0.
1 2 3 4 5 |
def hide(self): '''make player disappear from view''' self.hidden = True self.rect.center = (WINDOWWIDTH / 2, WINDOWHEIGHT + 100) # hide player below the screen self.hide_timer = pygame.time.get_ticks() |
In the collision detection earlier, when player.shield <= 0 we called player.hide( ). The hide( ) function will set self.hidden to True, and move the player “below” the window. We then set hide_timer equal to the current game time. Now let’s look at the update( ) function.
1 2 3 4 5 6 7 |
def update(self): '''update the player''' # unhide player if self.hidden and (pygame.time.get_ticks() - self.hide_timer > 1500): self.hidden = False self.rect.centerx = WINDOWWIDTH / 2 self.rect.bottom = WINDOWHEIGHT - 10 |
In line 4, we check if we are hidden and if 1.5 seconds has passed, and then reset the player back to the starting position in lines 6 and 7.
1 2 3 4 5 6 7 8 9 |
# fire weapons by holding the 'space' key if keys[pygame.K_SPACE] and not(self.rect.top > WINDOWHEIGHT): self.shoot() ###### OMITTED ###### # Stop player from being able to move or shoot # when at the bottom of the screen if self.rect.bottom > WINDOWHEIGHT + 10: self.rect.center = (WINDOWWIDTH / 2, WINDOWHEIGHT + 100) |
One last thing to note, in the update function we need to stop our players from being able to shoot or to be visible again. Therefore, we force the player to stay off the screen in lines 8 and 9.
Score
To create the scoring system in our space shooter is quite simple. First we need to create a function that will draw text to the screen.
1 2 3 4 5 6 7 |
def draw_text(surface, text, size, x, y, color): '''draw text to screen''' font = pygame.font.Font(pygame.font.match_font('arial'), size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() text_rect.midtop = (x, y) surface.blit(text_surface, text_rect) |
The draw_text function has six arguments: the surface window, the text we want to display, the size of the text, x and y position, and color of the text.
Then, we need to decide how much each enemy death is worth and update the score in the collision detection functions. If an asteroid is destroyed, the score depends on the size of the asteroid.
1 2 |
for hit in asteroid_hit: score += 50 - hit.radius # different scores for different size asteroids |
And if an enemy ship is destroyed:
1 2 |
for hit in enemy_hit: score += 75 |
I also added scores to the different pickups, 100 for the shield and 50 for the missiles, and added them to the code in a similar manner in the power up collision detection.
Displaying to the screen
The final step is to draw everything to the screen in the main game loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# draw/render DISPLAYSURF.fill(BLACK) # draw background image to game DISPLAYSURF.blit(background, background_rect) DISPLAYSURF.blit(planet, planet_rect) all_active_sprites.draw(DISPLAYSURF) DISPLAYSURF.blit(black_bar, (0,0)) pygame.draw.rect(DISPLAYSURF, GREY, (0, 0, WINDOWWIDTH, 35), 3) shield_bar(DISPLAYSURF, player.shield) # display score draw_text(DISPLAYSURF, "SCORE", 12, WINDOWWIDTH / 2, 2, WHITE) draw_text(DISPLAYSURF, str(score), 25, WINDOWWIDTH / 2, 12, WHITE) # display lives draw_lives(DISPLAYSURF, WINDOWWIDTH - 100, 5, player.lives, life_player_image) # done after drawing everything to the screen FPSCLOCK.tick(FPS) # number of FPS per loop pygame.display.flip() |
Here, we show everything that will be blitted to the game window. In line 8 and 9, we draw the black_bar. Line 10 calls the shield_bar function. Lines 13 and 14 draws the score to the screen. Finally in line 17 we draw the lives to the screen.

THE CODE FOR THIS TUTORIAL CAN BE FOUND ON GITHUB.
Summary
We’ve looked at how to display information, lives, score, and health, to the game window in this tutorial. Doing so allows the gamer to have a more interactive experience with the game and keep track of how they are progressing. Next time, we will complete our Space Fighter tutorial by adding game music, sounds, and a game menu.
Thank you for following along and please leave a comment if you have any questions or suggestions to make Red Huli better!