Skip to content

Making Your First Game, Part 2: Lighting

Introduction

This tutorial series will guide you towards making your first game in pygame-topdownengine! If you haven't completed the previous tutorial in this series, go back and finish that one and then come back here.

In this tutorial, we will be guiding you towards the (very simple) steps it takes to add lighting to your game in pygame-topdownengine. We will be continuing from the code from the previous tutorial, which you can find here.

But first... , let's talk scenes

In the last tutorial, we briefly went over the role of scenes in the engine. This time, let's talk more in depth.

All scenes are subclasses from the BaseScene class. Scenes have to define three methods: handle_event, update, and render. The handle_event method is called by the Game class during the event loop, and it takes in a pygame.Event object. The update method is called by the Game class during the update loop and takes in deltatime as a float. Finally, the render method is called by the Game class during rendering after the screen has been filled with Game.bg_color. It takes in no parameter.

For most projects, you will likely need to make your own scene classes, seeing as they control updates and rendering. However, for this tutorial, we will only be using the BaseScene class for the main menu and the GameplayScene class for the actual gameplay itself.

Light it up!

Now this whole talk about scenes may have you wondering, What does this remotely have to with lighting? Actually, a lot. The built-in lighting system that the engine comes with is actually integrated into the GameplayScene. The pre-built lighting system works by drawing a semi-transparent black Surface on top of the entire screen. Each GameObject has a light_radius attribute that is set to 0 on initialization. Using the position and light_radius of each GameObject, the GameplayScene draws circular "cut-outs" into the black Surface before it is blitted to the screen. The "cut-outs" are only drawn if light_radius is greater than 0.

The Global Alpha

The alpha value of the GameplayScene's black overlay (before light sources) is controlled by the GameplayScene.global_alpha attribute. On initialization, it is set to 0, which is why there was no lighting generated by the code from the previous tutorial.

Let's start writing code! Right before the game.run call from the previous tutorial code, add this code:

# Lighting
game.scenes["gameplay"].global_alpha = 150

As explained in the previous tutorial, the GameplayScene object is stored in Game.scenes["gameplay"] by default. So, this code simply retrieves that GameplayScene object and sets the global_alpha attribute to 150.

If you run the code right now, you should see the exact same menu as before. Once you click play, you should see the exact same gameplay, the only catch being that everything looks much darker now.

global_alpha

The global_alpha attribute must be between 0 and 255, inclusively.

Light Sources

Now that we have darkness, let's add light sources! Remember, to add light sources, all you need to do is set any GameObject's light_radius attribute to a number greater than 0. Right after the global_alpha assignment, add this code to make both the player and enemy light sources:

player.light_radius = 24
enemy.light_radius = 24

If you run the code now, you should see that both the player and enemy both have smooth circles of light around them. You should also notice that jumping will move the light up with you.

Conclusion

As always, you can view the example code on GitHub.