GMS 2 Shadow collision? (Need help/ideas)

W

Witzler

Guest
So I started two months ago (again) with Gamemaker Studio 2 and wanted to create a "solid" shadow for a little 2D Puzzle Platformer. Shadowcasting was no problem after following this Guide, but I can't figure out a good (not performance heavy) way to check for collision. Tried to check for for complete black color with 'draw_getpixel(x,y)' but it performs poorly. And after adding more code it didn't even want to update properly anymore.
Would be awesome if someone could help! I even would share my code/scripts, because it could be helpfull for everybody.

Forum.PNG
 

jo-thijs

Member
So I started two months ago (again) with Gamemaker Studio 2 and wanted to create a "solid" shadow for a little 2D Puzzle Platformer. Shadowcasting was no problem after following this Guide, but I can't figure out a good (not performance heavy) way to check for collision. Tried to check for for complete black color with 'draw_getpixel(x,y)' but it performs poorly. And after adding more code it didn't even want to update properly anymore.
Would be awesome if someone could help! I even would share my code/scripts, because it could be helpfull for everybody.

View attachment 13314
Hi and welcome to the GMC!

Do you mean that you attempt to make the player walk on shadows?
Pretty cool concept.

Anyway, what shapes do you want to check collision with shadows with?
Points? Rectangles? Arbitrary sprites?
 
W

Witzler

Guest
You are sure that it isn't mask related?
No, because it's only a drawing event that don't happen to mask itself (would be awesome so if GameMaker had an option for that)

Hi and welcome to the GMC!

Do you mean that you attempt to make the player walk on shadows?
Pretty cool concept.

Anyway, what shapes do you want to check collision with shadows with?
Points? Rectangles? Arbitrary sprites?
Yeah you got it! :)

All I want to check the shadow with is with the PlayerObject (square collision mask). The problem is that shadows can have any angle, so it would be nice if I could precisely check a drawn shadow.
[If I know how I can check for shadow collision, my next step would be to even check how steep a drawn shadow is (like a slope, but if it's too steep the player would slide off/ not be able to walk up).]
 

Bingdom

Googledom
Are the shadows going to be constantly changing, or are they going to remain the same place throughout the whole level?

If they're not moving, you can draw the shadows to a surface, turn the surface into a sprite and create a collision mask for that sprite using sprite_collision_mask()
 
W

Witzler

Guest
Are the shadows going to be constantly changing, or are they going to remain the same place throughout the whole level?

If they're not moving, you can draw the shadows to a surface, turn the surface into a sprite and create a collision mask for that sprite using sprite_collision_mask()
I thought about it, and no; the object that projects the shadows is not moving at all (but if someone would come up with an idea for moving shadow collision I would prefer it! as long as it isn't performance heavy)

Does this work to create a mask for a drawn shadow? (if it's not moving of course)
 

jo-thijs

Member
No, because it's only a drawing event that don't happen to mask itself (would be awesome so if GameMaker had an option for that)



Yeah you got it! :)

All I want to check the shadow with is with the PlayerObject (square collision mask). The problem is that shadows can have any angle, so it would be nice if I could precisely check a drawn shadow.
[If I know how I can check for shadow collision, my next step would be to even check how steep a drawn shadow is (like a slope, but if it's too steep the player would slide off/ not be able to walk up).]
Then you could try something like this:
Code:
var bx, by;
bx[4] = bbox_left;
bx[3] = bbox_left;
bx[2] = bbox_right + 1;
bx[1] = bbox_right + 1;
bx[0] = bbox_left;
by[4] = bbox_top;
by[3] = bbox_bottom + 1;
by[2] = bbox_bottom + 1;
by[1] = bbox_top;
by[0] = bbox_top;

with obj_light_source {
    for(var i = 0; i < 4; ++i) {
        if scr_collision_triangle_with_wall(bx[i], by[i], bx[i + 1], by[i + 1], x, y) {
            return true;
        }
    }
}

return false;
Then scr_collision_triangle_with_wall depends on some factors.
Are the walls in your project tile based?
If so, it can be made pretty efficiently.
 

Bingdom

Googledom
Does this work to create a mask for a drawn shadow? (if it's not moving of course)
No. You need a sprite for game maker to create the mask. Look at the function in the manual that I gave you.

It would also make the drawing process a lot faster, as you'll only need to draw the shadows once. Once it's applied to a surface and turned into a sprite, you just have to draw a simple large sprite.

You can do this process for moving shadows, but it would be very slow.
 

jo-thijs

Member
Are the shadows going to be constantly changing, or are they going to remain the same place throughout the whole level?

If they're not moving, you can draw the shadows to a surface, turn the surface into a sprite and create a collision mask for that sprite using sprite_collision_mask()
No. You need a sprite for game maker to create the mask.

It would also make the drawing process a lot faster, as you'll only need to draw the shadows once. Once it's applied to a surface and turned into a sprite, you just have to draw a simple large sprite.

You can do this process for moving shadows, but it would be very slow.
I'm having doubs with this approach.
It will work and it will work very efficiently if shadows indeed never change and if the room sizes don't get too large.
However, it feels like those 2 factors are quite limiting.
 
W

Witzler

Guest
Then you could try something like this:
Code:
var bx, by;
bx[4] = bbox_left;
bx[3] = bbox_left;
bx[2] = bbox_right + 1;
bx[1] = bbox_right + 1;
bx[0] = bbox_left;
by[4] = bbox_top;
by[3] = bbox_bottom + 1;
by[2] = bbox_bottom + 1;
by[1] = bbox_top;
by[0] = bbox_top;

with obj_light_source {
    for(var i = 0; i < 4; ++i) {
        if scr_collision_triangle_with_wall(bx[i], by[i], bx[i + 1], by[i + 1], x, y) {
            return true;
        }
    }
}

return false;
Then scr_collision_triangle_with_wall depends on some factors.
Are the walls in your project tile based?
If so, it can be made pretty efficiently.
Yeah, it is tile based! I have a seperate layer for that (following the Guide for shadow drawing).
But I have absolutely no plan how to go further on with this... If someone want the Project for shadow drawing I can upload a testroom with the light source, etc.
 
W

Witzler

Guest
I'm having doubs with this approach.
It will work and it will work very efficiently if shadows indeed never change and if the room sizes don't get too large.
However, it feels like those 2 factors are quite limiting.
And exactly this is my problem :/ But I would still work with it, if there is any way of checking for drawn events, like shadows.
 

jo-thijs

Member
And exactly this is my problem :/ But I would still work with it, if there is any way of checking for drawn events, like shadows.
Sorry, I'm an idiot.

My approach only works if the shape of the player is a single point (rather than an entire rectangle) or if there's only a single light.
How efficient it is depends on how many walls you've got and how far lights are placed with respect to the player's position and size.
On top of that, the code for it does not look nice.

It would have been better to reason in terms of being completely covered by light
as opposed to reason in terms of touching the absence of light.

Although I can tink of an algorithm to test for being covered by light,
it would be very time consuming and incredibly annoying to write (especially in GameMaker).

I suggest you go with the sprite conversion approach Bingdom suggested,
as you said it works for your project setup.

I did try to create an example using my approach,
but I ran into difficulties drawing shadows (I couldn't use shaders and I tried to only use a single surface)
and I ran into difficulties cecking for collisions (got lots of code and it has the issues mentioned above).
 
W

Witzler

Guest
Sorry, I'm an idiot.

My approach only works if the shape of the player is a single point (rather than an entire rectangle) or if there's only a single light.
How efficient it is depends on how many walls you've got and how far lights are placed with respect to the player's position and size.
On top of that, the code for it does not look nice.

It would have been better to reason in terms of being completely covered by light
as opposed to reason in terms of touching the absence of light.

Although I can tink of an algorithm to test for being covered by light,
it would be very time consuming and incredibly annoying to write (especially in GameMaker).

I suggest you go with the sprite conversion approach Bingdom suggested,
as you said it works for your project setup.

I did try to create an example using my approach,
but I ran into difficulties drawing shadows (I couldn't use shaders and I tried to only use a single surface)
and I ran into difficulties cecking for collisions (got lots of code and it has the issues mentioned above).
And thats exactly my problem too... :/
 
Top