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

Clearing Surfaces

I followed a somewhat out of date tutorial to build a simple lighting system I intend to expand, but while it works for the most part, the sprite bound to the mouse and the triangle primitives created by the walls leave behind afterimages like a windows 98 error.

I've gone through a few forums that have explored the issue but can't find a solution that works, so I'm going to ask here.

Here's the tutorial:

The code:

Create Event:
Code:
global.shadows = surface_create(1280, 720);
Begin Step:
Code:
surface_free(global.shadows);
global.shadows = surface_create(1280, 720);
surface_set_target(global.shadows);
draw_sprite(spr_light_test, -1, mouse_x, mouse_y);
End Step:
Code:
surface_reset_target();
Draw Event:
Code:
gpu_set_blendmode(bm_add);
draw_surface(global.shadows, 0, 0);
gpu_set_blendmode(bm_normal);
And the result, just to help clarify:

 
Full disclosure: I looked at the picture, skimmed the text, and saw you don't have any Draw End code (or at least, you didn't post it). I got stumped with this the first time too, so I'll give you what I needed to know.

Surfaces are just somewhere we can store drawing information. It acts like a canvas, because once you store all the vertex data (just points on a picture) on it, you can draw it all to the screen and that's how you get the picture. However, it's really just a text file of points. Once you write data to it, it stays like that until you tell it otherwise. If we're not using surfaces, GM handles all this in the background, but if we want to write data manually, we also have to clear the data manually. In the Draw End event, you're going to want to include something like this:
Code:
surf_set(surface);
draw_clear_alpha(0,0);
surf_reset();
Also, you should middle-mouse click 'surface_free' in your code. I think you'll find it's not doing what you think it is. 'Surface_free' deletes the surface from memory, so you're actually probably drawing all this to the application surface (the default one).
 
Last edited:
Full disclosure: I looked at the picture, skimmed the text, and saw you don't have any Draw End code (or at least, you didn't post it). I got stumped with this the first time too, so I'll give you what I needed to know.

Surfaces are just somewhere we can store drawing information. It acts like a canvas, because once you store all the vertex data (just points on a picture) on it, you can draw it all to the screen and that's how you get the picture. However, it's really just a text file of points. Once you write data to it, it stays like that until you tell it otherwise. If we're not using surfaces, GM handles all this in the background, but if we want to write data manually, we also have to clear the data manually. In the Draw End event, you're going to want to include something like this:
Code:
surf_set(surface);
draw_clear_alpha(0,0);
surf_reset();
Also, you should middle-mouse click 'surface_free' in your code. I think you'll find it's not doing what you think it is. 'Surface_free' deletes the surface from memory, so you're actually probably drawing all this to the application surface (the default one).

Yeah I know I need to clear the data, I'm just not sure HOW. If I don't include surface_free(global.shadows); in the set I get a memory leak and a crash.

There's currently no Draw Begin or Draw End event, though moving code around to them doesn't seem to do anything other than produce an error, "Trying to set texture that is also bound as depth buffer - bailing..."

Adding the code you suggested above also doesn't do anything.
 
Here, try this.
Code:
/// CREATE EVENT ///
// Just initialize the variable in the create event. Don't create the surface here, GM doesn't like that ;)
global.shadow_surface = -1;  // It is nice to have 'surface' in the name though.


/// STEP EVENT ///
// Draw the sprite how you want it. Make sure the instance running this code has an image_speed > 0.
surface_set_target(global.shadow_surface);
draw_sprite(spr_light_test, image_index, mouse_x, mouse_y);
surface_reset_target();


/// DRAW EVENT ///
// If there's no surface (i.e. it's -1), create a surface and bind it to this variable.
if !surface_exists(global.shadow_surface) global.shadow_surface = surface_create(1280, 720);

// Draw the surface with the correct blend mode. Draw Events come after Step Events so don't worry about having to use Begin Step.
gpu_set_blendmode(bm_add);
draw_surface(global.shadow_surface, 0, 0);
gpu_set_blendmode(bm_normal);

 
/// DRAW END EVENT ///
surface_set_target(global.shadow_surface);
draw_clear_alpha(0,0);  // It doesn't matter what colour you give it - it's going to be transparent.
surface_reset_target();
Read the comments, and make sure you look up any functions you don't understand in the Docs. This confusion you have is part of the process to becoming a better programmer. Learn to love it - it never goes away. :)
 
Here, try this.
Code:
/// CREATE EVENT ///
// Just initialize the variable in the create event. Don't create the surface here, GM doesn't like that ;)
global.shadow_surface = -1;  // It is nice to have 'surface' in the name though.


/// STEP EVENT ///
// Draw the sprite how you want it. Make sure the instance running this code has an image_speed > 0.
surface_set_target(global.shadow_surface);
draw_sprite(spr_light_test, image_index, mouse_x, mouse_y);
surface_reset_target();


/// DRAW EVENT ///
// If there's no surface (i.e. it's -1), create a surface and bind it to this variable.
if !surface_exists(global.shadow_surface) global.shadow_surface = surface_create(1280, 720);

// Draw the surface with the correct blend mode. Draw Events come after Step Events so don't worry about having to use Begin Step.
gpu_set_blendmode(bm_add);
draw_surface(global.shadow_surface, 0, 0);
gpu_set_blendmode(bm_normal);

 
/// DRAW END EVENT ///
surface_set_target(global.shadow_surface);
draw_clear_alpha(0,0);  // It doesn't matter what colour you give it - it's going to be transparent.
surface_reset_target();
Read the comments, and make sure you look up any functions you don't understand in the Docs. This confusion you have is part of the process to becoming a better programmer. Learn to love it - it never goes away. :)
Okay yeah I could not comprehend 💩💩💩💩 last night and looking over it again it all makes sense now. With a little rearranging it works just fine, thank you!

Now I gotta figure out blend modes so it's not just producing white cones.
 
Alright so now I have an issue with the wall sprites not blending with the flashlight sprite. I'm guessing I'm supposed to change the blendmode, waiting until the wall sprites get drawn to then change the blendmodes?
Issue it that I need to do that in the Draw End event or the Wall Sprites won't get drawn on top of the shadows they create, which is giving my brain conniptions.



Wall Code:

Create:

Code:
bwx = 32;
bwy = 32;

x1=0;
y1=0;
x2=0;
y2=0;
x3=0;
y3=0;
x4=0;
y4=0;

dirc = 0;

x11=0;
y11=0;
x21=0;
y21=0;
x31=0;
y31=0;
x41=0;
y41=0;

radius = 320;
Step:

Code:
if(distance_to_point(mouse_x,mouse_y) < radius)
{
    x1= x-bwx/2;
    y1= y-bwy/2;
    x2= x-bwx/2;
    y2= y+bwy/2;
    x3= x+bwx/2;
    y3= y+bwy/2;
    x4= x+bwx/2;
    y4= y-bwy/2;
    
    dirc = point_direction(mouse_x, mouse_y, x1, y1)
    x11 = x1+lengthdir_x(500, dirc);
    y11 = y1+lengthdir_y(500, dirc);
    
    dirc = point_direction(mouse_x, mouse_y, x2, y2)
    x21 = x2+lengthdir_x(500, dirc);
    y21 = y2+lengthdir_y(500, dirc);
    
    dirc = point_direction(mouse_x, mouse_y, x3, y3)
    x31 = x3+lengthdir_x(500, dirc);
    y31 = y3+lengthdir_y(500, dirc);
    
    dirc = point_direction(mouse_x, mouse_y, x4, y4)
    x41 = x4+lengthdir_x(500, dirc);
    y41 = y4+lengthdir_y(500, dirc);
    
    draw_set_color(c_black);
    draw_primitive_begin(pr_trianglestrip);
    draw_vertex(x1, y1); //this sets the point of the triagnle
    draw_vertex(x11, y11);
    draw_vertex(x2, y2);
    draw_vertex(x21, y21);
    draw_vertex(x3, y3);
    draw_vertex(x31, y31);
    draw_vertex(x4, y4);
    draw_vertex(x41, y41);
    draw_vertex(x1, y1); //this clsoes the shape
    draw_vertex(x11, y11);
    draw_primitive_end();
    draw_set_color(c_white);
}
Draw End:

Code:
if(distance_to_point(mouse_x,mouse_y) < radius)
{
    draw_set_color(c_white);
    draw_sprite(spr_light_test_wall, -1, x, y);
}
 
L

Lonewolff

Guest
Not seeing what is wrong from the image. What is the result you are looking for? Can you provide a mock up?
 
Top