We would love you to play this but your browser doesn't support HTML5 canvas.
Just use a different browser and you can happily play this game.

Advanced Lighting / Field of View (FoV) / Fog of War In GameMaker with Textures and Other Effects

First I want to say that the example above this is interactive and you can move the mouse around to change where the lighting comes from, all of the images below this are just pre-rendered images that you cant interact with.

I was playing This War of Mine and is has this really subtle FoV (Field of View) effect that slightly blurs out what the player cannot see. It’s a really good looking effect that might seem very hard to do in GameMaker however using this guide you shouldn’t have any problems putting it into your game.

This War of Mine FoV
So how are we going to do it:

We will do it in 3 quite simple steps:

First we will use the same lighting method I used in other guides however rather than drawing it onto the screen I will draw it onto a surface so everything the player can see is one colour and everything the player cannot see is a second colour.

GameMaker Lighting Mask

The next step is to take a copy of the screen onto a surface and modify the whole thing so it looks like how we want non visible areas to look.

The final step is just to use masking to take the outline of the light and use it to punch a hole in the new image of the screen. Once we draw this once the screen it will blur everything however the part the player can see will be a transparent hole that doesn’t get drawn so it will look normal through this gap.

How it will look:

For my example I have just used this subtle effect:

Final FoV in GameMaker with Blur, Darken and Static

This effect was made by adding these three different styles on top of each other:

Darken:

FoV in GameMaker with Darken

Blur:

FoV in GameMaker with Blur

Static:

FoV in GameMaker with Static

However using filters, different blend modes and your artistic style there are loads of cool effects you could put here!

Below is the code to do all this, however here is a copy of the GMZ that I used for the project at the top of this page.

obj_lighting CREATE
wallthatblock = ds_stack_create() // we keep a list of all walls in this

surfaceblur = surface_create(room_width, room_height); // how the room should look in the shadow
surfacewhatyoucansee = surface_create(room_width, room_height); // the mask of what the player can see
obj_lighting STEP
/// This is where you want the light source to be 
// you wont need this, this just needs to be x = obj_player.x or something like that 

// damn simple collisions for HTML version
if (place_meeting(mouse_x,mouse_y,obj_wall) == false) {
    // if the mouse is in a free space move light there otherwise use last point
    x = mouse_x
    y = mouse_y
}

/// find walls to cast shadows  

with(obj_wall) {

    /*
    but doing some if statments you can 
    find out if the person is above ot below the wall and then to the left or the right
    from this you know the two walls the line could be projected onto. 
    
    you when just need to work out which of the two walls is the best to project it onto 
    
    I think we can optermis this as well, 
     - do a collision line and dont bother to run this code on walls already behind another wall 
     - do a simple field of view and dont work out walls massively behind the person 
     - dont do walls off the screen
*/

    ds_stack_push(other.wallthatblock,id)
    
}
obj_lighting DRAW
/// MAKE A MASK THAT SHOWS WHERE THE PLAYER CAN SEE

// make sure the surface still exists and the graphics card hasnt deleted it 
if (! surface_exists(surfacewhatyoucansee)) {surfacewhatyoucansee = surface_create(room_width, room_height); }

surface_set_target(surfacewhatyoucansee)

// we are currently drawing on the surface so everything drawn here is not drawn onto the screen but onto the surface 

draw_clear_alpha(c_black,1) // make the whole surface black 

draw_set_blend_mode(bm_subtract) // remove all the places the player can see

// This is now the standard lighting I have done guides about before 
var numberoflinesimdrawing = ds_stack_size(wallthatblock)
var shadowsize = 1100

for (i=0; i<numberoflinesimdrawing; i++) {
    // draw_shadows
    draw_set_colour(c_black)

    wall = ds_stack_pop(wallthatblock)
    
    //draw_primitive_begin(pr_linestrip);
    draw_primitive_begin(pr_trianglestrip)
        draw_vertex(wall.bbox_left, wall.bbox_top);
        var dir = point_direction(x,y,wall.bbox_left,wall.bbox_top)
        draw_vertex(wall.x+lengthdir_x(shadowsize,dir), wall.y+lengthdir_y(shadowsize,dir));

        draw_vertex(wall.bbox_left, wall.bbox_bottom);
        var dir = point_direction(x,y,wall.bbox_left,wall.bbox_bottom)
        draw_vertex(wall.x+lengthdir_x(shadowsize,dir), wall.y+lengthdir_y(shadowsize,dir));

        draw_vertex(wall.bbox_right, wall.bbox_top);
        var dir = point_direction(x,y,wall.bbox_right,wall.bbox_top)
        draw_vertex(wall.x+lengthdir_x(shadowsize,dir), wall.y+lengthdir_y(shadowsize,dir));
 
        draw_vertex(wall.bbox_right, wall.bbox_bottom);
        var dir = point_direction(x,y,wall.bbox_right,wall.bbox_bottom)
        draw_vertex(wall.x+lengthdir_x(shadowsize,dir), wall.y+lengthdir_y(shadowsize,dir));

    draw_primitive_end()
    
    // normally you draw this under the walls so they dont get blurred out, 
    // if you do want walls hidden by the shadows add this line:
    //draw_rectangle(wall.bbox_left,wall.bbox_top,wall.bbox_right,wall.bbox_bottom,false)
    
};

// reset everything 
draw_set_blend_mode(bm_normal)
surface_reset_target();

// - Assert - At this point we have a mask called surfacewhatyoucansee that is black where the player cant see and transparent where they can 


/// MAKE A SURFACE OF THE WHOLE ROOM AND MANIPULATE IT TO LOOK LIKE HOW YOU WANT THE SHADOWS TO LOOK LIKE
// (we will cut out of this image what the player can see so those bits will not be displayed)

if (! surface_exists(surfaceblur)) {surfaceblur = surface_create(room_width, room_height); }

surface_set_target(surfaceblur)

/// ---- These are the edits I want to make: ----

// blur:
draw_set_alpha(0.5) // for some reason draw_set_alpha doesnt work on HTML5
draw_surface_ext(application_surface, 3, 3, 1, 1, 0, c_white, 0.5);
draw_surface_ext(application_surface, -3, 3, 1, 1, 0, c_white, 0.5);
draw_surface_ext(application_surface, 3, -3, 1, 1, 0, c_white, 0.5);
draw_surface_ext(application_surface, -3, -3, 1, 1, 0, c_white, 0.5);
draw_set_alpha(1)

// darken:
draw_set_alpha(0.15) // 0.15
draw_set_colour(c_black)
draw_rectangle(0,0,room_width,room_height,false)
draw_set_alpha(1)

// static:
draw_set_alpha(0.15) // 0.15
draw_sprite_tiled(spr_noise,0,irandom(50),irandom(50))
draw_set_alpha(1)


/// ---- Now we want to do the masking ----

// we are currently editing the blur surface so anything we draw here is not drawn to the screen but onto the surface

draw_set_blend_mode(bm_subtract)

draw_surface(surfacewhatyoucansee,0,0) // use blend mode subtract to cut the lighting mask out of the surface we blurred up 

draw_set_blend_mode(bm_normal)

surface_reset_target(); // reset everything 

draw_surface(surfaceblur,0,0) // draw all our work onto the screen (above the background but below the walls)

/// draw the location of the light (you dont need this)

draw_sprite(spr_light,0,x,y)

Now this does look long but I can assure you it is mostly comments!

I’m sure lots of you by now are trying to copy and paste that into a project. Unfortunately because of the GameMaker file I have running at the top of the screen it seems to capture keyboard inputs and blocks copy and paste from happening. This is really annoying, my teachers used to make me type out code from paper so you could do that, or there is a link here to a premade project file.

Other changes:

If you have a particular style to your game this would be the perfect place to make some really stylistic chooses. This War of Mine put this sketchy pencil drawing filter over the top of theirs and depending on the style of your game you could draw out or any other image for the fog of war.

Fog of War in GameMaker with Smoke

I have put some other examples down here of some other ways you can use this just by changing what sprites we use

Charcoal:

Fog of War in GameMaker with Charcoal

Ripples:

Fog of War in GameMaker with Ripples

Cells:

Fog of War in GameMaker with Cells

Something crazy you could do is rather than masking out what the player can’t see you mask out what they can. This would allow you to put a visual effect on what the player can see. I will leave you to come up with cool ideas you could do for this, but as an example here is an image of where I have just made it lighter where the player can see:

Lighting in GameMaker

In this example I have just made the area lighter, however you could use any texture or sprite to change this how you wanted.

Lighting in GameMaker
About the Article:
Hard Difficulty
GameMaker
By David Strachan
Get an E-mail when I post something new: Signup