How to fade image_alpha as you walk further from object

Pkirkby

Member
Hi everyone, as you can see from my image I have a simple light source. It's effective in drawing my shadow based on the placement of the light object. However, given my code I can't figure out how to properly fade the image_alpha out as I walk further from the light source. Here's the code I use:

var sx = oLighting.x - x;
var sy = oLighting.y - y;
//var light_xy = sx + sy;


//Draw Shadow

gpu_set_fog(true,c_black,0,1);
draw_sprite_pos(sprite_index,image_index,
x-(sprite_width/2)-sx,
y-sy,
x+(sprite_width/2)-sx,
y-sy,
x+(sprite_width/2),
y,
x-(sprite_width/2),
y,
image_alpha);

I've come close with some equations that update the alpha based on the x/y coordinates of the light source, but I'm too noobish in GML to figure this one out. Also, I've looked into the "clamp" function, this was on YoYo's website:

image_alpha = clamp(image_alpha - 0.01, 0, 1);

The above code will slowly reduce the image_alpha until it reaches 0.

Surely there must be a way to do this with clamp?

EDIT: Now I've got it working, HOWEVER I'm trying to make it so everywhere I place this "oLighting" object, I'd like it to cast a separate "shadow" and I can't seem to accomplish this.
 

Attachments

Last edited:

obscene

Member
Use point_distance() to find the distance between two points
Set the variable max_distance to distance at which alpha should be 0.

image_alpha=1-(actual_distance/max_distance);
 

Pkirkby

Member
Ok, so let's say my light source is called (oLight) How would I go about implementing that into my current code? Thanks for a fast response!
 
I got this to work in Gamemaker Studio 1.4.9999:
Code:
// if `distance` is below `min_distance` then the instance is fully visible
var min_distance = 32;
var max_distance = 256;
var distance = point_distance(oLighting.x, oLighting.y, x, y);
image_alpha = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);

var sx = oLighting.x - x;
var sy = oLighting.y - y;

//Draw Shadow

// gpu_set_fog(true,c_black,0,1);
draw_sprite_pos(
    sprite_index,
    image_index,
    x - sprite_width / 2 - sx,
    y-sy,
    x + sprite_width / 2 - sx,
    y-sy,
    x + sprite_width / 2,
    y,
    x - sprite_width / 2,
    y,
    image_alpha);
 

Pkirkby

Member
I got this to work in Gamemaker Studio 1.4.9999:
Code:
// if `distance` is below `min_distance` then the instance is fully visible
var min_distance = 32;
var max_distance = 256;
var distance = point_distance(oLighting.x, oLighting.y, x, y);
image_alpha = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);

var sx = oLighting.x - x;
var sy = oLighting.y - y;

//Draw Shadow

// gpu_set_fog(true,c_black,0,1);
draw_sprite_pos(
    sprite_index,
    image_index,
    x - sprite_width / 2 - sx,
    y-sy,
    x + sprite_width / 2 - sx,
    y-sy,
    x + sprite_width / 2,
    y,
    x - sprite_width / 2,
    y,
    image_alpha);
Damn, I'm not sure what I'm doing wrong, is that exactly as you did it to get it work?
 

Pkirkby

Member
Nev

Nevermind, I got it!!! Dude, you've solved an issue I've been struggling with for weeks lol. Thanks again!
Here's another question for you, when I make this an object, it only affects things in one instance, if I put multiple of these objects, they dont make individual shadows on the objects. Would you know a way around that?
 

obscene

Member
Sounds like you have one object to run the effect, right?

Best way to run code for multiple instances is something like this...

with (obj_name) { do stuff }

This will cause every obj_name to run the following code all at once.

So with multiple lights and multiple shadowcasters you might end up with something like this...

Code:
with (obj_light)
   {
   // save the lights position to temporary variables
   var xx=x;
   var yy=y;
   
   with (obj_shadowcaster)
          {
          // get distance from x,y to xx,yy and draw the shadows at x,y
          }
   }
 
  • Like
Reactions: Yal

Pkirkby

Member
Sounds like you have one object to run the effect, right?

Best way to run code for multiple instances is something like this...

with (obj_name) { do stuff }

This will cause every obj_name to run the following code all at once.

So with multiple lights and multiple shadowcasters you might end up with something like this...

Code:
with (obj_light)
   {
   // save the lights position to temporary variables
   var xx=x;
   var yy=y;
  
   with (obj_shadowcaster)
          {
          // get distance from x,y to xx,yy and draw the shadows at x,y
          }
   }
Actually I already have it affecting any objects in my associated with my oParent, my problem is that I want this code to affect all "lamps" for example. So I want to place a bunch of "lamps" and have a shadow draw for each lamp's light source. But as of right now, it only seems to draw one. Thanks again for your reply.
 

obscene

Member
That's where "with" comes in. If you write with(obj_lamp) every lamp runs the code. Not sure if your code is in your shadowcaster objects or in a controller object, but in either case that's the way to approach it.

In your code in your first post, you are just saying...

var sx = oLighting.x - x;
var sy = oLighting.y - y;

But that will only get one light.

This will get them all...

Code:
with (oLighting)
   {
   var sx=x; // this code is running from the perspective of each light instance, so simply get x and y.
   var sy=y;
   with (oParent)
      {
      // draw your shadow here for each object as you did before.
      }
   }
 

Pkirkby

Member
Yeah, I didn't post my with statement, it currently has a "with (oParent)" to affect all objects controlled by my parent object. But Im going to try that tonight, it's kind of what I was thinking but it's nice to see it from someone more experienced. Thanks a lot for your help!
 

Pkirkby

Member
That's where "with" comes in. If you write with(obj_lamp) every lamp runs the code. Not sure if your code is in your shadowcaster objects or in a controller object, but in either case that's the way to approach it.

In your code in your first post, you are just saying...

var sx = oLighting.x - x;
var sy = oLighting.y - y;

But that will only get one light.

This will get them all...

Code:
with (oLighting)
   {
   var sx=x; // this code is running from the perspective of each light instance, so simply get x and y.
   var sy=y;
   with (oParent)
      {
      // draw your shadow here for each object as you did before.
      }
   }
So I tried that, but it seems that if I remove the "sx = oLighting.x - x;" it won't update the shadow based on the position of the object, it just fixes it. I can't seem to have each light source affect each object.

While we're here, I'm trying to apply an if statement of similar effect, where as my zsp (my jumping height) increases, the shadow size decreases. I should be able to use a similar statement, but how would you go about it?
 

Pkirkby

Member
You'll need to post your entire code. As it stands, sx = oLighting.x - x; shouldn't be a part of your code anywhere.

Read this in case you're unsure about how "with" works...

https://docs.yoyogames.com/source/dadiospice/002_reference/001_gml language overview/401_18_with.html

Also, is this top-down or sidescroller?
This is a Top-down style game, as of right now I have "oLighting" working and affecting all objects, I just cant place more than one "oLighting" and have multiple shadows cast from each source. Here's my current code:

with(oParent)
{
//variables for shadows
var min_distance = 2;
var max_distance = 150;
var distance = point_distance(oLamp.x, oLamp.y+z, x, y+z);
var shadow_alpha = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
var shadow_distance = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);

var sx = oLamp.x - x;
var sy = oLamp.y - y;

//Draw Shadow


gpu_set_fog(true,c_black,0,1);
draw_sprite_pos(
sprite_index,
image_index,
x - sprite_width / 2 - sx,
y-sy,
x + sprite_width / 2 - sx,
y-sy,
x + sprite_width / 2,
y,
x - sprite_width / 2,
y,
shadow_alpha);


//draw_sprite_ext(sprite_index,image_index,x-5,y-5,image_xscale,image_yscale,0,c_black,0.5);

//This sets fog to disable,white is default.
gpu_set_fog(false,c_white,0,0);


}
 
I got this to work:
Code:
// gpu_set_fog(true,c_black,0,1);

with(oLighting) // assuming all `oLighting` instances cast light
{
    // jumping (z)
    var cast_dir = point_direction(x, y, other.x, other.y);
    var xcast = lengthdir_x(other.z, cast_dir) + other.x;
    var ycast = lengthdir_y(other.z, cast_dir) + other.y;

    // variables for shadows
    var min_distance = 2;
    var max_distance = 150;
    var distance = point_distance(x, y, xcast, ycast);
    var shadow_alpha = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
    var shadow_distance = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
   
    var sx = x - xcast;
    var sy = y - ycast;
   
    // draw shadow
    draw_sprite_pos(
        other.sprite_index,
        other.image_index,
        xcast - other.sprite_width / 2 - sx,
        ycast - sy,
        xcast + other.sprite_width / 2 - sx,
        ycast - sy,
        xcast + other.sprite_width / 2,
        ycast,
        xcast - other.sprite_width / 2,
        ycast,
        shadow_alpha);
}

// This sets fog to disable, white is default.
// gpu_set_fog(false,c_white,0,0);
As your `z` increases the shadow should appear farther away.
 

Pkirkby

Member
I got this to work:
Code:
// gpu_set_fog(true,c_black,0,1);

with(oLighting) // assuming all `oLighting` instances cast light
{
    // jumping (z)
    var cast_dir = point_direction(x, y, other.x, other.y);
    var xcast = lengthdir_x(other.z, cast_dir) + other.x;
    var ycast = lengthdir_y(other.z, cast_dir) + other.y;

    // variables for shadows
    var min_distance = 2;
    var max_distance = 150;
    var distance = point_distance(x, y, xcast, ycast);
    var shadow_alpha = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
    var shadow_distance = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
  
    var sx = x - xcast;
    var sy = y - ycast;
  
    // draw shadow
    draw_sprite_pos(
        other.sprite_index,
        other.image_index,
        xcast - other.sprite_width / 2 - sx,
        ycast - sy,
        xcast + other.sprite_width / 2 - sx,
        ycast - sy,
        xcast + other.sprite_width / 2,
        ycast,
        xcast - other.sprite_width / 2,
        ycast,
        shadow_alpha);
}

// This sets fog to disable, white is default.
// gpu_set_fog(false,c_white,0,0);
As your `z` increases the shadow should appear farther away.
Awesome, I'm going to try tomorrow. Appreciate the response!
 

Pkirkby

Member
I got this to work:
Code:
// gpu_set_fog(true,c_black,0,1);

with(oLighting) // assuming all `oLighting` instances cast light
{
    // jumping (z)
    var cast_dir = point_direction(x, y, other.x, other.y);
    var xcast = lengthdir_x(other.z, cast_dir) + other.x;
    var ycast = lengthdir_y(other.z, cast_dir) + other.y;

    // variables for shadows
    var min_distance = 2;
    var max_distance = 150;
    var distance = point_distance(x, y, xcast, ycast);
    var shadow_alpha = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
    var shadow_distance = 1 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 1);
  
    var sx = x - xcast;
    var sy = y - ycast;
  
    // draw shadow
    draw_sprite_pos(
        other.sprite_index,
        other.image_index,
        xcast - other.sprite_width / 2 - sx,
        ycast - sy,
        xcast + other.sprite_width / 2 - sx,
        ycast - sy,
        xcast + other.sprite_width / 2,
        ycast,
        xcast - other.sprite_width / 2,
        ycast,
        shadow_alpha);
}

// This sets fog to disable, white is default.
// gpu_set_fog(false,c_white,0,0);
As your `z` increases the shadow should appear farther away.
Ok, so I fooled around with it, I am trying to make sense of it. What's the "other" object and how is it controlled? Seems I get an issue with the "object.z" right off the bat.
 

Pkirkby

Member
Anyone have any more suggestions? I've read up on With but I still can't seem to have all objects "oLamp" draw shadow, only the most recent "oLamp" will affect other objects. I have my "oLighting" affecting my "oParent" which essentially affects everything that should cast a shadow, and I made oLamp the reference point in which the light is cast. As you can see from the screenshot, light is casting from the right lightsource but wont from the left. Here's my code, any help would be amazing, thanks!



with(oParent)
{
//variables for shadows
var min_distance = 2;
var max_distance = 150;
var distance = point_distance(oLamp.x, oLamp.y, x, y);
var shadow_alpha = 0.8 - clamp((distance - min_distance) / (max_distance - min_distance), 0, 0.8);

var sx = oLamp.x - x;
var sy = oLamp.y - y;

//Draw Shadow


gpu_set_fog(true,c_black,0,1);
draw_sprite_pos(
sprite_index,
image_index,
x - sprite_width / 2 - sx,
y-sy,
x + sprite_width / 2 - sx,
y-sy,
x + sprite_width / 2,
y,
x - sprite_width / 2,
y,
shadow_alpha);



//draw_sprite_ext(sprite_index,image_index,x-5,y-5,image_xscale,image_yscale,0,c_black,0.5);

//This sets fog to disable,white is default.
gpu_set_fog(false,c_white,0,0);

}
 

Attachments

Top