GameMaker Tutorial: Dynamic Lighting Using a Surface Method (Beginner Friendly)

This tutorial teaches you how to create a dark room with a circular light around your player using a surface.
This method is reliable, works on all runtimes, and avoids common blend‑mode problems.


What You’ll Create

  • A darkness layer covering the whole room
  • A hole “cut” in the darkness where the player is
  • Smooth, dynamic lighting that follows movement
  • Optional soft glow and multiple lights

STEP 1 — Create obj_lightmask

Create a new object called obj_lightmask.
This should have NO sprite.


STEP 2 — Add a Create Event

This sets up a surface and lighting variables:

// CREATE EVENT of obj_lightmask

surf_dark = -1; // storage for the lighting surface

dark_alpha = 0.9; // how dark the room is (0 = none, 1 = pitch black)

light_radius = 140; // size of the light circle

STEP 3 — Add a Draw End Event

This is the core of the lighting system.
(Draw End ensures the lighting draws on top of the game.)

Copy and paste this:

// DRAW END EVENT of obj_lightmask

// 1. Create the surface if it doesn't exist

if (!surface_exists(surf_dark)) {

surf_dark = surface_create(room_width, room_height);

}

// 2. Start drawing ONTO the surface

surface_set_target(surf_dark);

// Clear it (fully transparent to begin with)

draw_clear_alpha(c_black, 0);

// 3. Draw semi-transparent black over the whole room

draw_set_color(c_black);

draw_set_alpha(dark_alpha);

draw_rectangle(0, 0, room_width, room_height, false);

// 4. Subtract light to carve a hole

gpu_set_blendmode(bm_subtract);

// Light position (player position)

var lx = obj_player.x;

var ly = obj_player.y;

// Draw white circle to subtract from darkness

draw_set_color(c_white);

draw_set_alpha(1);

draw_circle(lx, ly, light_radius, false);

// Reset blend and alpha

gpu_set_blendmode(bm_normal);

draw_set_alpha(1);

// 5. Stop drawing to surface

surface_reset_target();

// 6. Draw the finished surface back to the screen

draw_surface(surf_dark, 0, 0);

STEP 4 — Place obj_lightmask in the Room

Place it anywhere in the room, but ensure it is on a top instance layer(see Below):

  1. Open your room in the Room Editor.
  2. On the left panel, find the Layers list.
    You’ll see something like:
    • Instances
    • Instances_2
    • Background
    • Tiles
    • etc.
  3. Create a new instance layer (right‑click → “Add Layer” → “Instance Layer”).
  4. Name itLighting
  5. Drag the Lighting layer to the TOP of the list.

What “top” means

The layer must be at the top of the list, because the list draws from bottom → top.

So it should look like:

Lighting        <-- obj_lightmask goes here
Instances
Instances_2
Background

The lighting layer will now:

  • Darken the room
  • Cut a circular light around the player

Optional Upgrade — Soft Glow Blend

For smoother, more natural lighting, replace:

draw_circle(lx, ly, light_radius, false);

with:

draw_circle_colour(lx, ly, light_radius, c_white, c_black, false);


This creates a soft gradient instead of a sharp edge.


Optional Upgrade — Multiple Lights

You can “cut out” several lights by adding more draw calls:

draw_circle(obj_player.x, obj_player.y, 140, false);

draw_circle(obj_torch.x, obj_torch.y, 120, false);

draw_circle(obj_enemy.x, obj_enemy.y, 80, false);


Each circle becomes a light source.


Troubleshooting

Black screen? Try these:

  • The player object name might be different → test with var lx = 320; var ly = 180;
  • You didn’t use Draw End → must be Draw End event
  • The surface may not exist → restart the room after adding it
  • The layer order is wrong → ensure obj_lightmask is on top