Skip to content

Lighting system

Lucas Hicks edited this page Sep 13, 2023 · 10 revisions

Lighting System

To enhance the game and make the game time feel more meaningful, a day/night cycle has been implemented. This complements the existing game time display by adding brightness and darkness to the game during day and night respectively. To implement this system, a 2D lighting framework for LibGdx has been used called Box2dLights. This lighting framework uses Box2d for all of its raycasting which is helpful as this is the 2D physics engine that is used in this game engine. This framework provides a vast number of lighting features; however, to keep the lighting system within the game style and to reduce CPU burden, very little of the dynamic lighting features are used.

Box2DLights overview

There is very little helpful documentation out there on box2dlights so I will try my best to add some.

LightService

In order to manage everything related to lights updating and rendering, box2dlights uses a RayHandler class. This RayHandler class uses the World from the PhysicsEngine in order to handle all of the collision geometry for the lighting. In order to readily access this RayHandler in order to create lights across the game, the LightService has been created, which essentially acts as a wrapper class for the RayHandler following the design patterns similar to the other services seen in the ServiceLocator. Additionally, this LightService is accessible through the ServiceLocator as lighting may not be restricted to the main game area as it could be used on other screens (eg: main game screen, loading screens, etc.).

Usage

AuraLightComponent

Player Lighting

Rendering of the lights

As the lights are all registered with the RayHandler instance, they are all kept track of and easily drawn using the updateAndRender() method of the RayHandler. In order for the lights to be drawn in the correct order and not be drawn over important ui components, the render() method in the Renderer class was modified. This method is shown below:

  public void render() {
    Matrix4 projMatrix = camera.getProjectionMatrix();
    batch.setProjectionMatrix(projMatrix);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.begin();
    renderService.render(batch);
    batch.end();
    if (ServiceLocator.getLightService() != null) {
      ServiceLocator.getLightService().renderLight();
    }
    debugRenderer.render(projMatrix);

    stage.act();
    stage.draw();
  }

The order of rendering here is quite simple, as is as follows:

  1. Anything renderable with a sprite is rendered by the RenderService. This includes the player, animals, items, the map, etc.
  2. The lights are then rendered by the LightService with the renderLight() method.
  3. The game UI is then rendered as it is part of the stage.

When creating new visual components, you need to determine whether or not they will be drawn before or after the lights are drawn and hence decide whether they should be part of the game stage or not.

Clone this wiki locally