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 circleSTEP 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):
- Open your room in the Room Editor.
- On the left panel, find the Layers list.
You’ll see something like:- Instances
- Instances_2
- Background
- Tiles
- etc.
- Create a new instance layer (right‑click → “Add Layer” → “Instance Layer”).
- Name it →
Lighting - 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_lightmaskis on top