1. Hey! Guest! The XXX GMC Jam will take place between August 24th, 12:00 UTC (Friday noon) and August 27th, 12:00 UTC (Monday noon). Why not join in! Click here to find out more!
    Dismiss Notice

GML [solved] Wavy / Teared Screen FX Using Surfaces (draw_surface_part)

Discussion in 'Programming' started by Nikles, Feb 26, 2018.

  1. Nikles

    Nikles Member

    Joined:
    Jun 21, 2016
    Posts:
    38
    Hi folks!
    I'm currently experiencing a brain fart and I need your help.

    I'm creating a wavy/tearing effect (gif below). How do I make it seamlessly repeat forever? Because as it is right now it just keeps moving all those surfaces outside the display. And they never cycles back.

    If I reset the sy (screen y) to 0 it will cycle back but I get a jittery effect (just like the bad loop below)

    [​IMG]

    Here's the code in the create event of my controller:
    Code:
    sy = 0 
    Here's the post draw event
    Code:
    
    var as = application_surface
    var dw = display_width
    var dh = display_height
    
    var band_num    = 16
    var band_height    = dh / band_num
    
    for (var current_band = 0; current_band < band_num * 2; current_band++)
    {
        draw_surface_part(as, 0, 0 + band_height * current_band - sy, dw, band_height, 0 + sin(current_band) * 32 , 0 + band_height * current_band - sy)
    }
    
    sy += 4
    
    if (band_height * band_num - sy + band_height) <= 0
        sy = 0
    
    
    Can you help me implement a seamless loop?

    EDIT:
    I've edited the above code to highlight what's going on; I'm looping blindly at random here because I can't wrap my head around it. Right now I have zero ideas on how to approach the issue. Any input is appreciated.

    [​IMG]
     
    Last edited: Feb 26, 2018
  2. 2Dcube

    2Dcube Member

    Joined:
    Jun 23, 2016
    Posts:
    269
    I'm not sure I fully understand your code.
    But I'm thinking you need to reset sy at the exact right moment. Since sy increases with 4 every step,
    Code:
    if sy > 4 * band_height * band_num
    {
        sy = 0
    }
    ? I could be wrong.
     
  3. Bingdom

    Bingdom Googledom

    Joined:
    Jul 1, 2016
    Posts:
    1,625
    I'd suggest looking at using mod or %. Here's why.

    I haven't fully looked at your code, so I'm going to generalise it.

    If you have a value that you know it won't approach to 0 for a long time (but in your case, you're setting it to 0 at a wrong time), don't directly set it as 0 when it surpasses the max value. Once the timer (or offset) becomes greater than the max value, you do timer - maxValue to reset it. This is where modulo can take place (It's a bit different from subtraction though). Modulo divides a number by a number then returns the remainder.

    A code example:
    Code:
    yOffset = (yOffset + speed) % maxValue
    In this example, yOffset will never be > maxValue. It would always get wrapped back to the remainder.

    PS: This can be done much more efficiently through a shader.
     
    Last edited: Feb 27, 2018
  4. Nikles

    Nikles Member

    Joined:
    Jun 21, 2016
    Posts:
    38
    Thank you. It doesn't really work but I appreciate your suggestions.

    There's probably something flawed in the way I'm approaching the problem here but I can't see what.
    I might as well try the shader route but I feel like I might be facing the same "rewind jitterness" / "out of synch looping" effect.
     
  5. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    4,966
    Why not use a sine wave? A sine wave goes from -1 to 1,so you'd multiply the value by how far you want it to deviate. Maybe 16 in your case. I think (not sure) it'd be sin(current_band/band_number)*16
     
  6. Nikles

    Nikles Member

    Joined:
    Jun 21, 2016
    Posts:
    38
    I am using a sine wave but each band horizontal position must stay fixed (and not oscillate).
    So each band has its own horizontal position defined as
    Code:
    0 + sin(current_band) * 32
    (and yes don't consider the "0 + ")
     
  7. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    4,966
    Oh yeah. My phone cut it off lol.

    ...
    So does your code draw the surface like

    Code:
    0
        1
            2
                3
                    4
                        5
    But then just using sy to essentially shify the surface up?

    Try modifying the sin value instead of the surface offset.

    sin(current_band + sy) * 32

    Then just increase sy by 1 instead of 4. You can loop it back to 0 when it reaches band_num*2.

    sy = (sy+1) mod (band_num*2);
     
  8. Nikles

    Nikles Member

    Joined:
    Jun 21, 2016
    Posts:
    38
    None of the solutions above actually worked but they gave me the correct ideas so thank you all!

    This is the correct code
    Code:
    var as = application_surface
    var dw = display_width
    var dh = display_height
    
    var band_num    = 16
    var band_height    = dh / band_num
    
    for (var current_band = 0; current_band < band_num * 2; current_band++)
    {
        draw_surface_part(as, 0, 0 + band_height * current_band - sy, dw, band_height, 0 + sin( (degtorad(360) / band_num ) * current_band) * 32 , 0 + band_height * current_band - sy)
    }
    
    sy = (sy + 4) % (band_height * band_num) // Loops here.
    
    
    As you can see I now use the following code to find the X offset of the bands:
    Code:
    sin( (degtorad(360) / band_num ) * current_band) * 32
    Using degtorad(360) / band_num ensures that I complete a cycle without jitters. So I can then safely loop with (sy + 4) % (band_height * band_num).

    I can vary the speed of the waves as well by increasing or decreasing the value I add (or subtract) to sy.

    Thank you all again!
     
    2Dcube 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