• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shaders Overlapping Shadows

Tobey

Member
So basically what I'm trying to do is create a shadow as if the light source was behind everything like this:
upload_2019-8-28_16-3-11.png

However, I need this to show everything such as the sword swing which does work but the swinging arm is a separate sprite, so when I draw the shading for it, it looks like this:
upload_2019-8-28_16-8-15.png
As you can see, the body shadow is darker where the sword shadow is. So how would I fix this? I have been trying different things for a while such as blend modes, this didn't work (but that could have been because I don't really understand blend modes).

Here's the code which is in the draw event of the player:
Code:
draw_self();

draw_sprite_ext(sprite_index, image_index, x, y, -1, 0.9, 180, c_black, 0.5);
    if(instance_exists(obj_player_back_arm)){
        draw_sprite_ext(player_back_arm, 0, x + 11, y + 56, 1, -0.9, -obj_player_back_arm.image_angle, c_black, 0.5);
    }

    if(instance_exists(obj_player_front_arm)){
        draw_sprite_ext(player_front_arm, 0, x - 16, y + 57, 1, -0.9, -obj_player_front_arm.image_angle, c_black, 0.5);
    }

    if(instance_exists(obj_player_left_arm)){
        draw_sprite_ext(player_left_arm, 0, x, y + 54, 1, -0.9, -obj_player_left_arm.image_angle, c_black, 0.5);
    }

    if(instance_exists(obj_player_right_arm)){
        draw_sprite_ext(player_right_arm, 0, x, y + 54, 1, -0.9, -obj_player_right_arm.image_angle, c_black, 0.5);
    }
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Okay, what you should do here is create a controller object and in that make a surface the size of the camera view. Then in the draw event, clear the surface to an alpha of zero and then draw all the shadows you require using a FULL alpha of 1. You would then draw this surface to the screen with the alpha you want to have the shadows at. So, basically this:

Code:
// CREATE EVENT
surf = -1;

// DRAW EVENT
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh  = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
surface_set_target(surf);
draw_clear_alpha(c_black, 0);
with (OBJECT) // do this for all objects that you want to have shadows, replacing "OBJECT" for the object name
    {
    // OBJECT SHADOW DRAW CODE HERE WITH FULL ALPHA
    }
surface_reset_target();
var _xx = camera_get_view_x(_cam);
var _yy camera_get_view_y(_cam);
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
Make sure to put the controller object on a layer that will be under everything else too!
 
Last edited:

Tobey

Member
Okay, what you should do here is create a controller object and in that make a surface the size of the camera view. Then in the draw event, clear the surface to an alpha of zero and then draw all the shadows you require using a FULL alpha of 1. You would then draw this surface to the screen with the alpha you want to have the shadows at. So, basically this:

Code:
// CREATE EVENT
surf = -1;

// DRAW EVENT
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh  = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
surface_set_target(surf);
draw_clear_alpha(c_black, 1);
with (OBJECT) // do this for all objects that you want to have shadows, replacing "OBJECT" for the object name
    {
    // OBJECT SHADOW DRAW CODE HERE WITH FULL ALPHA
    }
surface_reset_target();
var _xx = camera_get_view_x(_cam);
var _yy camera_get_view_y(_cam);
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
Make sure to put the controller object on a layer that will be under everything else too!
In the "with(OBJECT){" line, could I use a parent object instead like this: "with(shadow_parent){"?

EDIT: I tested with a parent object and it does work, however; when I run the code I get this error:
Code:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Draw Event
for object obj_shading_control:

local variable _yy(100005, -2147483648) not set before reading it.
 at gml_Object_obj_shading_control_Draw_0 (line 34) - draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_shading_control_Draw_0 (line 34)
I did try the code without a parent object and still got this error, so it has nothing to do with that.
 
Last edited:

Nocturne

Friendly Tyrant
Forum Staff
Admin
That error indicates you haven't declared the _yy variable... which is because of a typo in my code (sorry) :( The "var" declaration is missing the "=" sign... Btw, ARE you using views? If not then the code can be made even simpler, but if you are I forgot to tell you to offset the object drawing by the current view x/y position (you need to do this as when you target a surface, it is essentially positioned at the (0,0) position, so you need to make sure what you're drawing is in that space). So, with offset drawing the code would be more like this:

Code:
// CREATE EVENT
surf = -1;

// DRAW EVENT
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
var _xx = camera_get_view_x(_cam);
var _yy = camera_get_view_y(_cam);
surface_set_target(surf);
draw_clear_alpha(c_black, 0);
with (OBJECT) // do this for all objects that you want to have shadows, replacing "OBJECT" for the object name
    {
    // OBJECT SHADOW DRAW CODE HERE WITH FULL ALPHA AND OFFSET BY THE VIEW POSITION, EG:
    draw_sprite_ext(player_back_arm, 0, (x + 11) - _xx, (y + 56) - _yy, 1, -0.9, -obj_player_back_arm.image_angle, c_black, 1);
    }
surface_reset_target();
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
If the code is still not working for you, you need to post what you have so I can revise it. :)
 

Tobey

Member
That error indicates you haven't declared the _yy variable... which is because of a typo in my code (sorry) :( The "var" declaration is missing the "=" sign... Btw, ARE you using views? If not then the code can be made even simpler, but if you are I forgot to tell you to offset the object drawing by the current view x/y position (you need to do this as when you target a surface, it is essentially positioned at the (0,0) position, so you need to make sure what you're drawing is in that space). So, with offset drawing the code would be more like this:

Code:
// CREATE EVENT
surf = -1;

// DRAW EVENT
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
var _xx = camera_get_view_x(_cam);
var _yy = camera_get_view_y(_cam);
surface_set_target(surf);
draw_clear_alpha(c_black, 1);
with (OBJECT) // do this for all objects that you want to have shadows, replacing "OBJECT" for the object name
    {
    // OBJECT SHADOW DRAW CODE HERE WITH FULL ALPHA AND OFFSET BY THE VIEW POSITION, EG:
    draw_sprite_ext(player_back_arm, 0, (x + 11) - _xx, (y + 56) - _yy, 1, -0.9, -obj_player_back_arm.image_angle, c_black, 1);
    }
surface_reset_target();
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
If the code is still not working for you, you need to post what you have so I can revise it. :)
That error indicates you haven't declared the _yy variable... which is because of a typo in my code (sorry) :( The "var" declaration is missing the "=" sign... Btw, ARE you using views? If not then the code can be made even simpler, but if you are I forgot to tell you to offset the object drawing by the current view x/y position (you need to do this as when you target a surface, it is essentially positioned at the (0,0) position, so you need to make sure what you're drawing is in that space). So, with offset drawing the code would be more like this:

Code:
// CREATE EVENT
surf = -1;

// DRAW EVENT
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
var _xx = camera_get_view_x(_cam);
var _yy = camera_get_view_y(_cam);
surface_set_target(surf);
draw_clear_alpha(c_black, 1);
with (OBJECT) // do this for all objects that you want to have shadows, replacing "OBJECT" for the object name
    {
    // OBJECT SHADOW DRAW CODE HERE WITH FULL ALPHA AND OFFSET BY THE VIEW POSITION, EG:
    draw_sprite_ext(player_back_arm, 0, (x + 11) - _xx, (y + 56) - _yy, 1, -0.9, -obj_player_back_arm.image_angle, c_black, 1);
    }
surface_reset_target();
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
If the code is still not working for you, you need to post what you have so I can revise it. :)
I tried the code but now everything is darker and the shadow isn't being drawn at all.

Here's my code:
Code:
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
var _xx = camera_get_view_x(_cam);
var _yy = camera_get_view_y(_cam);
surface_set_target(surf);
draw_clear_alpha(c_black, 1);
with (obj_shading_parent) // do this for all objects that you want to have shadows, replacing "OBJECT" for the object name
    {
    // OBJECT SHADOW DRAW CODE HERE WITH FULL ALPHA AND OFFSET BY THE VIEW POSITION, EG:
    draw_sprite_ext(sprite_index, image_index, x - _xx, y - _yy, -1, 0.9, 180, c_black, 1);
    if(instance_exists(obj_player_back_arm)){
        draw_sprite_ext(player_back_arm, 0, (x + 11) - _xx, (y + 56) - _yy, 1, -0.9, -obj_player_back_arm.image_angle, c_black, 1);
    }

    if(instance_exists(obj_player_front_arm)){
        draw_sprite_ext(player_front_arm, 0, (x - 16) - _xx, (y + 57) - _yy, 1, -0.9, -obj_player_front_arm.image_angle, c_black, 1);
    }

    if(instance_exists(obj_player_left_arm)){
        draw_sprite_ext(player_left_arm, 0, x - _xx, (y + 54) - _yy, 1, -0.9, -obj_player_left_arm.image_angle, c_black, 1);
    }

    if(instance_exists(obj_player_right_arm)){
        draw_sprite_ext(player_right_arm, 0, x - _xx, (y + 54) - _yy, 1, -0.9, -obj_player_right_arm.image_angle, c_black, 1);
    }
    }
surface_reset_target();
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
And here's what the game looks like now:
upload_2019-8-28_17-38-7.png
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Okay, almost there! Here's an edited version that should work:

Code:
var _cam = view_camera[0]; // or use camera_get_default() to get the default cam in the room
if !surface_exists(surf)
{
var _ww = camera_get_view_width(_cam);
var _hh = camera_get_view_height(_cam);
surf = surface_create(_ww, _hh);
}
else
{
var _xx = camera_get_view_x(_cam);
var _yy = camera_get_view_y(_cam);
surface_set_target(surf);
draw_clear_alpha(c_black, 0);
with (obj_shading_parent)
    {
    draw_sprite_ext(sprite_index, image_index, x - _xx, y - _yy, -1, 0.9, 180, c_black, 1);
    }
with (obj_player_back_arm)
    {
    draw_sprite_ext(player_back_arm, 0, (x + 11) - _xx, (y + 56) - _yy, 1, -0.9, -obj_player_back_arm.image_angle, c_black, 1);
    }
with (obj_player_front_arm)
    {
    draw_sprite_ext(player_front_arm, 0, (x - 16) - _xx, (y + 57) - _yy, 1, -0.9, -obj_player_front_arm.image_angle, c_black, 1);
    }
with (obj_player_left_arm))
    {
    draw_sprite_ext(player_left_arm, 0, x - _xx, (y + 54) - _yy, 1, -0.9, -obj_player_left_arm.image_angle, c_black, 1);
    }
with (obj_player_right_arm)
    {
    draw_sprite_ext(player_right_arm, 0, x - _xx, (y + 54) - _yy, 1, -0.9, -obj_player_right_arm.image_angle, c_black, 1);
    }
surface_reset_target();
draw_surface_ext(surf, _xx, _yy, 1, 1, 0, c_black, 0.5); // Set alpha value to what you require
}
While the idea of using a parent is fine for shadows, in this case it's not going to work correctly as you have a load of different offsets for the different instances, so just call "with" like I do above and you'll be fine (if the instance doesn't exist, then the code just won't run, and it won't error).
 
Top