Simple Lighting (Surfaces)

As requested, I’d like to do a quick entry about simple lighting systems in Game Maker Studio. The following does not use any extensions or complex code. All you will need is a controller object and some basic knowledge of how surfaces work in Game Maker.


Instead of going to far in depth about this, I’ll just show you what I’m doing and I’ll let you do some further research if you’d like to accomplish more with your lighting system.

To begin, you will need an object that will handle your lighting. In my project, I call it ‘objDarkRoom’ because it actually makes the room dark as well as handling the light sources.

CREATE EVENT


// Create a surface the size of the current room
// You could also create a surface the size of the current view, but I won't get into that
surf = surface_create(room_width, room_height);

// The following two lines clear the surface
// There is no guarantee that the surface doesn't contain garbage info post-creation
surface_set_target(surf);
draw_clear_alpha(c_black, 0);

// Reset to application surface
surface_reset_target();

STEP EVENT


// Surfaces are volatile 
// Always check that they haven't been destroyed 
if (surface_exists(surf)) {
    surface_set_target(surf);

    // The following three lines set the 'dark' overlay
    draw_set_color(c_black);
    draw_set_alpha(0.8);
    draw_rectangle(0, 0, room_width, room_height, 0);

    // Setting the blend mode to 'subtract' is what allows us to "cut holes" out of the overlay
    draw_set_blend_mode(bm_subtract);
    draw_set_color(c_white);
    
    // Draw circles in the overlay with your different light sources
    // Note that I add randomization to the position and radius to mimic a flicker effect
    with (oLantern)
        draw_circle(x + random_range(-1, 1), y + random_range(-1, 1), 30 + random_range(-1, 1), false);
            
    with (oParticleLantern)
        if (image_xscale > 0.25)
            draw_circle(x + random_range(-1, 1), y + random_range(-1, 1), 2 + random_range(-1, 1), false);
    
    // Reset all of your draw stuff
    draw_set_blend_mode(bm_normal);
    draw_set_alpha(1);
    surface_reset_target();
} else {
    // Again, surfaces can be a pain
    // Create a new one if there were issues
    surf = surface_create(room_width, room_height);
    surface_set_target(surf);
    draw_clear_alpha(c_black, 0);
    surface_reset_target();
}

// Apparently I moved my fog layer with 'objDarkRoom', haha
background_x[1] -= 0.5;

ROOM END EVENT


// Clean up the surface memory manually
if (surface_exists(surf)) 
    surface_free(surf);

DRAW END EVENT

NOTE: I am using the DRAW END EVENT rather than the DRAW EVENT. I'm not sure if there is any drawback to this. I use it because I can guarantee that 'objDarkRoom' will run its draw code LAST. If you use the typical draw event, be sure that this object is on the highest layer (lowest number), otherwise objects/tiles could draw on top of the overlay.


// Draw the surface or create a new one
// Be sure to use views, even if it isn't necessary for your game
// This trick bypasses an issue with resizing the game window
// DX requires that surfaces be destroyed when resizing
if (!surface_exists(surf)) {
    surf = surface_create(room_width, room_height);
} else {
    if (view_current == 0) {
        draw_surface(surf, 0, 0);
    }
}

Questions, comments, concerns? Shoot me an email at zbell91[AT]comcast[DOT]net.

-Z

Simple Lighting (Surfaces)

2 thoughts on “Simple Lighting (Surfaces)

    1. DirectX requires that all surfaces be destroyed when resizing a window. There is currently no way around that. I believe there is an event pertaining to window resizing. You could create a new, resized one.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s