Revealing an area with a surface

M

maxta12

Guest
Hey guys I'm having a really hard time figuring this out, I need suggestions on how I could proceed.. I'm making a TDS that has different office areas, and corridors (for example), but I don't want anything inside these rooms/areas to be visible until the door has been opened. So far what I have is drawing a surface that covers the entire game room (view_surface) and a code that reveals a room pretty much exactly how I want it, but its so dang cpu intensive its not even funny, here's my code (which is in my door's draw event) (also this is tailored right now for a sliding door that is facing up/down):
Code:
draw_self()
//set temp vars
var xleftscan = false;
var xrightscan = false;
var yupscan = false;
var ydownscan = false;
var xleftscan2 = false;
var xrightscan2 = false;
if first_open = false
{
//upscan
//start by dealing with the width of the line
    //left x stretch
for (i=0;i<500;i+=1)//i can be considered the max the line will extend
{
    if !collision_line(x,y+line1_y,x-i,y+line1_y,wall,1,1)
    {
        xleftscan = true
        surface_set_target(obj_view_region.view_surface)
        draw_set_blend_mode(bm_subtract)
        draw_line(x,y+line1_y,x-i,y+line1_y)
        draw_set_blend_mode(bm_normal)
        surface_reset_target()
    }
    else
    {
    xleftscan = false
    }
    //right x stretch
    if !collision_line(x,y+line1_y,x+i,y+line1_y,wall,1,1)
    {
        xrightscan = true
        surface_set_target(obj_view_region.view_surface)
        draw_set_blend_mode(bm_subtract)
        draw_line(x,y+line1_y,x+i,y+line1_y)
        draw_set_blend_mode(bm_normal)
        surface_reset_target()
    }
    else
    {
    xrightscan = false
    }
}
//1.check that both sides have been maxed out on the x axis
//2.move up on the y axis
if xleftscan = false
{
    if xrightscan = false
    {
       if !collision_line(x,y,x,y+line1_y+1,wall_horizontal,1,1)
       {
            yupscan = true
            line1_y += 1
       }
       else
       {
       yupscan = false
       }
           
    }
}
//downscan
//start by dealing with the width of the line
    //left x stretch
for (ii=0;ii<500;ii+=1)//i can be considered the max the line will extend
{
    if !collision_line(x,y+line2_y,x-ii,y+line2_y,wall,1,1)
    {
        xleftscan2 = true
        surface_set_target(obj_view_region.view_surface)
        draw_set_blend_mode(bm_subtract)
        draw_line(x,y+line2_y,x-ii,y+line2_y)
        draw_set_blend_mode(bm_normal)
        surface_reset_target()
    }
    else
    {
    xleftscan2 = false
    }
    //right x stretch
    if !collision_line(x,y+line2_y,x+ii,y+line2_y,wall,1,1)
    {
        xrightscan2 = true
        surface_set_target(obj_view_region.view_surface)
        draw_set_blend_mode(bm_subtract)
        draw_line(x,y+line2_y,x+ii,y+line2_y)
        draw_set_blend_mode(bm_normal)
        surface_reset_target()
    }
    else
    {
    xrightscan2 = false
    }
}
//1.check that both sides have been maxed out on the x axis
//2.move down on the y axis
if xleftscan2 = false
{
    if xrightscan2 = false
    {
       if !collision_line(x,y,x,y+line2_y-1,wall_horizontal,1,1)
       {
            ydownscan = true
            line2_y -= 1
       }
       else
       {
       ydownscan = false
       }
           
    }
}
}
and in the create event what is also relevant:
Code:
line1_y = 0
line2_y = 0
first_open = true
I'm really looking for suggestions on either how to improve this code to be much less cpu intensive or a better way to reveal only certain rooms within the game room. Any help thoughts or questions are appreciated! :)
 
A

anomalous

Guest
How do you know what room number you are in?
Are walls orthogonal?
Do you use tiles?
Is this static or dynamic walls/room size?

A general method is to just pre-generate the coordinates above. So basically use what you have, but run this during design and not in the game itself (or as you go periodically,etc.) but add a few more steps:
1. have another pass that combines line segments (?) such that you have a small/smallest set of coordinates needed to define rectangles that cover your room.
2. write that to a file (ds_grid or list or whatever you used above), and include it to load when that level loads, and just access those coordinates...no need to generate during the game.
If include files are to be avoided, you can output some GLM code adding those coordinates in a script or something.

Obviously that only works for static rooms. If they are dynamic walls, etc, that won't work.
 
M

maxta12

Guest
Thanks anomalous for the reply!
My walls aren't orthogonal
I dont use tiles
These are static walls and room sizes (which of course vary with level design and such). I was considering using some kind of grid system and just activating the (tiles?) that arent in contact with wall but once again I feel like that could be quite demanding. Or what do you think about creating an object, making it create its own surface (which has the size of the object's sprite), then just checking for collision with player and then making it go invisible while player is in the room, and as soon as he leaves, black surface reappears. That way its possible to put that object in the room, resize it to fit as an overlay for any corridor/in-game room. At that point I would wonder is it safe to use many smaller individual surfaces or does that end up being demanding as well?

As for your idea, that could very well work, any idea how I could go about joining those line segments up? I am fine with using a ds_grid aswell, I used something similar before with pathfinding. I will seriously consider working with coordinates as that does sound a lot easier on the cpu than just drawing tons and tons of lines until a room is cleared up haha
 
C

ConsolCWBY

Guest
I once read of a very old way of doing this, iirc, is to create a list of rectangular coordinates and use the draw rectangles function to block out all areas - except fot the player's coordinates. An early form of masking. MrDave has been experimenting with a more modern approach to this problem, here is his thread: https://forum.yoyogames.com/index.php?threads/masking-in-gamemaker-with-surfaces.123/
If all else fails, I'd contact him. :)
Sorry if I couldn't be of more help!
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Here's my suggestion... Use tiles. Add "roof" tiles over the areas that you want to hide, and make sure that each roof is on a different layer. Then make an invisible controller object that detects the player (this can be in a collision event or using collision circle or whatever) and place this in the "door" to the area. Finally, in the ROOM CREATE EVENT for the controller instance set a variable to the tile depth that you want to expose.

So, you have tiles, a controller, and a depth. Now in the controller object when you check for the player, simply use the depth variable to hide the tile layer at that depth. :)

This method is WAY more intuitive than using surfaces, requires far less code, and lets you visually plan out your rooms.
 
M

maxta12

Guest
@Nocturne Hey thanks for that idea, I'm trying to implement it at the moment but I'm really struggling with one simple thing haha: where you said to set a variable to the depth that I want to expose, I'm trying to get the the controller object to get the depth of the tile that it is touching/that is covering it, and I'm not quite sure how to make that happen since tiles arent objects. I tried this funky thing that didnt do what I wanted: my_tile_depth = tile_get_depth(instance_nearest(x,y,FOW)) //FOW being the cover tile (and this was inserted in the room creation code). Basically I'm not sure how I would go about getting the controller object to detect the depth of its cover region (if that makes sense :) )

*Quick update* I gave a value manually to the controller object and it works exactly as intended. But I still need to figure out how to make that object detect what layer its associated to, unless I want to make a new controller object for every different room...

@ConsolCWBY Also I want to thank you for your input on the topic aswell! I'm giving the tile idea a shot but your idea could have been a way of doing it also ;)
 
Last edited by a moderator:

Nocturne

Friendly Tyrant
Forum Staff
Admin
Okay, if you are using the room editor, when you place the controller in the room, you can right-click on the instance and select "Creation Code". This opens a code editor for code that is specific to the instance and will be run after the create event, making it an ideal place to set variable like this. So in the Creation Code you set the depth variable for the tile layer that you want to show/hide. If you must do it with code, then make sure your tile layers are all equally spaced in depth (so -100, -110, -120, etc....) and then do a loop to get the one that is actually over the controller:
Code:
for (var i = -100; i < -1000; i -= 10;)
{
if tile_layer_find(i, x, y)
    {
    my_tile_depth = i;
    break;
    }
}
 
M

maxta12

Guest
Just saw your reply thanks a lot man your help is really appreciated! I'll go with manually setting the objects depth.. I can't believe I didn't know you could change the creation code of specific instances in the room, that's going to be really useful in the future! I think I can pretty much consider this solved since that was the only missing part in what I was trying to do. Thanks again man you really cleared that up for me :)
 
Top