• 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!

Top down water reflections?

S

SirPandaMaster

Guest
I'm making a top-down open world game and I need to know how I would go about having water reflect he world around it. Think of it as if you were looking down at a lake, and seeing the reflections of the world around it. How would I accomplish this? Should I do it with a shader (not great with those)? Or is there some other way. I tried to reflect with surfaces the world around the single spot, but haven't found a way that works. This is what the top down camera looks like.Screenshot 2018-10-11 20.46.00.png
 

lolslayer

Member
I've worked on this before, and there's one major problem with the setup, and that's that you need sprites for the bottoms of the sprite-based characters.

But when you have those sprites, you just draw the whole world again, but you flip the z-axis (height) around the ground height (multiplying z/height with -1 is probably enough in your case).
You also need to be certain that the reflected objects are drawn behind the ground, and then you poke transparent holes in the ground where you want it to reflect
 
Heh, ya got me thinking. One way of doing this is to create a surface for the water, draw the water sprite on the surface, set the blend mode to only draw on pixels that have an alpha above 0 on the source, draw your water, decide what objects to draw based off their distance from the pool, invert their positions using draw_sprite_pos to correctly match the way they should be reflected and then draw the surface. Which looks like this:

water_effect.gif

Here's the code (it's not commented, super sloppy as I was just rushing it out and ALSO, if I was using it in-game, I'd try to limit the draws to the surface, but that's kinda hard with the animated water going on and I'd also move some of the calculating out of the Draw Event):

Create event
Code:
surf = -1;
t = 0;
t2 = 0;
t3 = 0;
water_count_max = sprite_get_number(sprite9);
water_count = 0;
Draw Event
Code:
if (!surface_exists(surf)) {
   surf = surface_create(sprite_width*2,sprite_height*2);
}
if (water_count < water_count_max) {
   water_count += 0.05;
}
else {
   water_count = 0;
}
var point_x,point_y;
point_x = x;
point_y = y;
var width = sprite_width;
var height = sprite_height;
water_id = id;
t+=0.25; // These are all just timers for the sine wave I'm using to make the sprite move around like it's in water
t2+=0.1;
t3+=0.05;
var _t = t;
var _t2 = t2;
var _t3 = t3;

surface_set_target(surf);
draw_sprite(sprite_index,0,sprite_width,sprite_height);
gpu_set_blendmode_ext(bm_dest_alpha,bm_inv_src_alpha);
draw_set_color(c_aqua);
draw_sprite(sprite9,floor(water_count),sprite_width,sprite_height);
with (obj_town_player) {
   if (point_distance(x,y,point_x,point_y) < 100) {
       var top_bulge = sin(_t); // These bulges and grows move the sprite like it's in water
       var bot_bulge = sin(_t2);
       var grow = sin(_t3);
       var xx = (x-point_x+width)-(sprite_width/2);
       var yy = (y-point_y+height)+(sprite_height/2);
       draw_sprite_pos(sprite_index,0,xx-top_bulge,yy+sprite_height+grow,xx+sprite_width+top_bulge,yy+sprite_height+grow,xx+sprite_width+bot_bulge,yy,xx-bot_bulge,yy,0.5);
   }
}
gpu_set_blendmode(bm_normal);
surface_reset_target();

draw_surface(surf,x-sprite_width,y-sprite_width);
 
@Schwee Yeah, that's true, but it all depends on the style the artist is going for. You could simply reflect the sky, perhaps with some wandering clouds, etc, but I think it feels better and adds more dynamism if you reflect the things on the ground around the water body. It all comes back to the old argument about realism vs fun. People have to make up their own minds about that in relation to the project they're working on.
 

Schwee

Member
@Schwee Yeah, that's true, but it all depends on the style the artist is going for. You could simply reflect the sky, perhaps with some wandering clouds, etc, but I think it feels better and adds more dynamism if you reflect the things on the ground around the water body. It all comes back to the old argument about realism vs fun. People have to make up their own minds about that in relation to the project they're working on.
Agreed, and as long as the user doesn't see something off during play then it's fair game.
 
Hi @SilentxxBunny . I've got two solutions for you. I managed to get @RefresherTowel 's code to work for me, but since I'm doing a game where the player can have customizable clothes that are drawn overtop of the player, it didn't end up looking right. If you're simply just drawing the player in the reflection however, it should work fine!

This would go in your draw event:
Code:
if(!surface_exists(watersurf))
{
    watersurf = surface_create(sprite_width*2,sprite_height*2);  
}

var point_x = x;
var point_y = y;

var width = sprite_width;
var height = sprite_height;

t += 0.15; //these are all just timers for the sine wave I'm using to make the sprite move around like it's in water
t2 += 0.05;
t3 -= 0.05;

var _t = t;
var _t2 = t2;
var _t3 = t3;

var ref_alpha = reflect_alpha;

surface_set_target(watersurf);

draw_sprite(sprite_index,image_index,sprite_width,sprite_height);
gpu_set_blendmode_ext(bm_dest_alpha,bm_inv_src_alpha);

if(instance_exists(obj_player))
{
    with(obj_player)
    {
        if(point_distance(x,y,point_x,point_y) < 200)
        {
            var top_bulge = sin(_t); //These create the water distortion effect (as the value gets higher the sin value fluxuates between -1 and 1
            var bot_bulge = sin(_t2);
            var grow = sin(_t3);
       
            var xx = (x - point_x + width) - (sprite_width/2);
            var yy = (y - 14 - point_y + height) + (sprite_height/2);
            var nx = x - point_x + width;
            var ny = y - point_y + height + 11;
            var adj = 5;
            draw_sprite_pos(sprite_index, image_index,xx - top_bulge + adj, yy + sprite_height + grow - adj, xx + sprite_width + top_bulge - adj, yy + sprite_height + grow - adj, xx + sprite_width + bot_bulge - adj/2, yy, xx - bot_bulge + adj/2,yy,ref_alpha);

gpu_set_blendmode(bm_normal);
surface_reset_target();

draw_set_alpha(0.4);

//draw_surface(watersurf,x - sprite_width,y - sprite_width);

draw_set_alpha(1.0);
***That's the code I was able to get work for me. However as I mentioned I am drawing clothes on top of the player, so the draw_sprite_pos function wasn't working for me. However if I instead use draw_sprite_ext and just set the yscale to -1 I can draw my clothes properly. However now I have to figure out how to get a wavy effect for the water surface, so I did some more searching and found this page: https://forum.yoyogames.com/index.p...en-fx-using-surfaces-draw_surface_part.43435/
which I was able to use to create a subtle but similar effect.

Hope that helps! :)
 
Top