Masking in GameMaker with surfaces

Discussion in 'Tutorials' started by MrDave, Jun 20, 2016.

  1. MrDave

    MrDave Member

    Joined:
    Jun 20, 2016
    Posts:
    76
    GM Version: GameMaker Studio
    Target Platform: All (including HTML5)
    Download: http://www.davetech.co.uk/files/gamemakermasking.gmz
    Links: http://www.davetech.co.uk/gamemakermasking

    Summary:
    A guide on how to use surfaces to do masking in GameMaker. This allows you to erase parts of the image so you can see through them.


    Tutorial:
    See the download link above to get the guide. Sorry it has to be on an external website but I think it is important to see the interactive demo at the top to understand the power of masking.

    [​IMG]
     
    Last edited: Jun 20, 2016
  2. chance

    chance predictably random Forum Staff Moderator

    Joined:
    Apr 22, 2016
    Posts:
    791
    Both links take me to the web page with the written guide. I don't see a GM source file for download -- which is what I expected "download" to mean. Perhaps that's an oversight, but in this case either way is fine. The online tutorial is clear, and you've provide the relevant code sample. (Personally, I prefer to see actual downloads. Because that allows me to quickly check for errors or bugs, when the example is more extensive.)

    Anyway... nice little tutorial here. Your illustrations and discussion should be easy for beginners to follow. And I'm sure members can find lots of fun uses for this technique. Nice job.
     
  3. MrDave

    MrDave Member

    Joined:
    Jun 20, 2016
    Posts:
    76

    Thanks for the feedback, I updated the post to include a project file. I will make sure I do that in the future.
     
    slojanko likes this.
  4. itameio

    itameio Member

    Joined:
    Jun 21, 2016
    Posts:
    57
    this is amazing!, i can think of a couple of ways to use this (with credit ofcourse), appreciated!
     
  5. Jaqueta

    Jaqueta Member

    Joined:
    Jun 23, 2016
    Posts:
    338
    Awesome!
    This is specially useful with shaders, like, adding radial blur only on the edges and things like this...

    Another thing that would be cool is creating a custom Primitive with Raycasting, that would show only the players Field of view in a top down game... He would be able to see the world normally, but the enemies would appear only on the mask.

    Really useful, thanks! It will be used, and I will give you credits ;D
     
  6. MrDave

    MrDave Member

    Joined:
    Jun 20, 2016
    Posts:
    76
    I have actually done both of those but I want to make sure the article is well written before I post it out: Top down casting shadows and Top down field of view
     
    mariospants and Jaqueta like this.
  7. mariospants

    mariospants Member

    Joined:
    Jun 21, 2016
    Posts:
    94
    Dave, this stuff is pretty damn inspirational, thanks for sharing!
     
  8. Muetdhivers

    Muetdhivers Guest

    Very interesting stuff here.
    my two cent about you code example :
    I try your code on the page http://www.davetech.co.uk/lighttechdemo2
    as written in the page, it doesn't work as intended.
    you reference the x and y of the player without using other.x and other.y inside a with statement, you need to change that to make it work.

    otherwise i learn some interesting stuff from that example, so thanks !
     
    MrDave likes this.
  9. MrDave

    MrDave Member

    Joined:
    Jun 20, 2016
    Posts:
    76
    Wow well spotted! I had to check my code but it is because I used a for() in my project and changed it to a with() on the website as I thought it was more obvious what was going on. It's fixed now.

    Thanks for that. And thanks for looking at my other tutorials.
     
  10. Juju

    Juju Member

    Joined:
    Jun 20, 2016
    Posts:
    406
    Hi Dave, good job on the masking guide.

    I do, however, have concerns about your shadow casting / line of sight examples. Your lengthdir-based solution is very wasteful and isn't the most efficient way of achieving the desired effect. Resources are always at a premium, nowhere moreso than HTML5.

    You'd be better off using Cartesian coordinates and scaling them up relative to the light's position. You can achieve a fixed distance at the expense of using an inverse square-root or, better yet, have very large triangles and not worry about a maximum size. The code is not significantly more complex (in my opinion, it's actually simpler) and can still serve as a pedagogical tool.
     
  11. Muetdhivers

    Muetdhivers Guest

    @Juju, could you write an example of what you are talking about ? (i'm very bad at math, and a beginner in coding, but i'm really interested in that kind of think).
     
  12. Juju

    Juju Member

    Joined:
    Jun 20, 2016
    Posts:
    406
    Sure, here's some code:
    Code:
    var _ox = x;
    var _oy = y;
    var _a_large_number = 10000;
    var _dx, _dy;
    
    draw_set_colour( c_black );
    
    with( obj_wall ) {
    
        draw_primitive_begin( pr_trianglestrip );
    
        draw_vertex( bbox_left, bbox_top );
    
        _dx = bbox_left - _ox;
        _dy = bbox_top - _oy;
        draw_vertex( x + _dx * _a_large_number, y + _dy * _a_large_number );
    
        draw_vertex( bbox_left, bbox_bottom );
    
        _dx = bbox_left - _ox;
        _dy = bbox_bottom - _oy;
        draw_vertex( x + _dx * _a_large_number, y + _dy * _a_large_number );
    
        draw_vertex( bbox_right, bbox_top );
    
        _dx = bbox_right - _ox;
        _dy = bbox_top - _oy;
        draw_vertex( x + _dx * _a_large_number, y + _dy * _a_large_number );
    
        draw_vertex( bbox_right, bbox_bottom );
    
        _dx = bbox_right - _ox;
        _dy = bbox_bottom - _oy;
        draw_vertex( x + _dx * _a_large_number, y + _dy * _a_large_number );
    
        draw_primitive_end();
    
    }
    If you want to control the maximum length of each scaled vector - which I doubt is even necessary since a GPU will clip all polygons to the viewport - you can use a slightly different format that uses an inverse square-root:
    Code:
    ...
        _dx = bbox_left - _ox;
        _dy = bbox_top - oy;
        _n = 1 / sqrt( _dx*_dx + _dy*_dy ); //This should be var'd prior to the "with" loop
        draw_vertex( x + _dx * _n * _distance, y + _dy * _n * _distance );
    ...
    
    ...where _distance is the scaled vector's length. Note the manual use of Pythagoras rather than point_distance - function/script calls have a non-trivial overhead and if you're calling a script thousands of times every frame then you need to manage the CPU load carefully. Also, this fixed length method naturally fails when _dx and _dy equal 0. It's best to simply avoid this outcome by making sure lights are never in positions where this is true; however, if this isn't acceptable for some reason then a simple point-in-rectangle check should be done beforehand to work around it.
     
    Last edited: Jul 9, 2016
  13. MrDave

    MrDave Member

    Joined:
    Jun 20, 2016
    Posts:
    76
    Hey Juju, thanks for your feedback. I will change the code because I think you are right. However both really are equally as good. You say you “Have concerns” Well you shouldn’t. I spent ages just performance comparing our codes and got identical results (as best you can on a computer running as many programs), 50% of the time yours performed better, 50% mine performed better.

    You specifically say about performance on HTML5 and having a non-trivial overhead well I actually went through the source output to actually find the exact code that gets run behind the scenes by GameMaker when you use point_direction() and you will find the code is very trivial:

    Code:
    function _06(_U8,_V8,_g8,_h8){var _a4=_g8-_U8;var _b4=_h8-_V8;if(_a4===0){if(_b4>0)return 270.0;else if(_b4<0)return 90.0;else return 0.0}else {var _6v=180.0*Math.atan2(_b4,_a4)/_H8;_6v=(~~round(_6v*1000000))/1000000.0;if(_6v<=0.0){return -_6v}else {return(360.0-_6v)}}return _Tt}
    Like I said you are right, but I think you are over dramatizing the problem. We are talking about a small amount of simple maths every frame.
     
  14. Juju

    Juju Member

    Joined:
    Jun 20, 2016
    Posts:
    406
    Taking to PM to avoid derailing the surface masking discussion.
     
    MrDave likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice