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

GM:S 1.4 A Quirk in Precise Sprite / Object Collision with Filled Squares

Discussion in 'Programming' started by Steneub, Jun 12, 2019.

  1. Steneub

    Steneub Member

    Joined:
    Jun 3, 2019
    Posts:
    10
    I have discovered a quirk in how precise collision is determined with the collision_line() function.
    upload_2019-6-12_6-22-30.png
    Using a small sprite (8x8) with one color and several frames as a map* for collision, most of which are angled slopes and one frame as a solid block, I learned that this solid block does not behave as if Precise Collision is enabled.

    The documentation clearly states:
    Which the sprite does have Precise enabled, which is why the other tiles work the way they should. This quirk has been causing me to pull my hair out.

    The engine treats this frame as imprecise, so I must do two checks to be sure the player object is colliding with instances of this collision object.

    Code:
        var c = collision_line( x1, y1, x2, y2, obj_collision, true, true );
        if (c == noone) c = collision_line( x1, y1, x2, y2, obj_collision, false, true );
        if (c != noone) {
            collision_direction[i] = true;
        }
    I know this is 1.4 and not going to get fixed, but is there a way around this quirk other than doing this the way I'm doing it?

    * For a little context, I have an object read the tile data and spawn corresponding objects referencing the appropriate shape.
     
  2. Nocturne

    Nocturne Friendly Tyrant Forum Staff Admin

    Joined:
    Apr 13, 2016
    Posts:
    6,777
    Do you have "separate collision masks" flagged as well as "precise" in the sprite collision properties?
     
  3. Steneub

    Steneub Member

    Joined:
    Jun 3, 2019
    Posts:
    10
    Yes, I do!

    upload_2019-6-12_7-26-18.png
     
  4. Misty

    Misty Member

    Joined:
    Jun 22, 2016
    Posts:
    1,019
    I dont get it. I have never seen collision code like this before, so it doesnt make sense to me.

    Normally, most collision systems check for a bounding box, then if inside bounding box, enable detailed collisions.

    Your collisions seem to do it in reverse. The code first checks for precise collisions, if no collision is found, then it goes to imprecise collisions. Is this what you intended?
     
  5. Steneub

    Steneub Member

    Joined:
    Jun 3, 2019
    Posts:
    10
    My intention was to do pixel-perfect collisions against an arbitrarily rotated rectangle (as I type this, I'm having a bit of a light-bulb moment, so I'll continue here, but then share my realization afterwards).

    The game is a top-down driving game, and I want to know if my rotated bounding box is in contact with any of the race track's walls (or will be in the next frame). Relative to the center of the vehicle object, I calculate the locations of the four corners and then use collision_line() to check whether there are any collisions between those points.
    Code:
    // "fp" stands for footprint, and I have already calculated the x,y positions for each of the four corners of the footprint
    // collision_dirs is an enum with D_FRONT, D_LEFT, D_RIGHT, and D_REAR as stand-ins for 0,1,2,3
    
    for (var i = collision_dirs.D_FRONT; i <= collision_dirs.D_REAR; i++) {
        switch (i) {
            case collision_dirs.D_FRONT:
                var x1 = fp_front_left_x;
                var y1 = fp_front_left_y;
                var x2 = fp_front_right_x;
                var y2 = fp_front_right_y;
                break;
        /*snip*/
        }
        var c = collision_line( x1, y1, x2, y2, obj_collision, true, true );
        if (c == noone) c = collision_line( x1, y1, x2, y2, obj_collision, false, true );
        if (c != noone) {
            collision_direction[i] = true;
        }
    }
    
    My assumption was that collision_line() with the precision "true" should have been enough to catch anything in between those two line. The solution you're seeing here is a "well, screw it" grasp at straws that says if it fails the desired way, then fall-back to something else that might work. It does work and performance on my potato computer is unhindered so I'm tempted to leave it as is. If optimization is an issue, I can fiddle with things here.

    HOWEVER

    I can probably skip this precise collision checking that I'm doing and rely on the engine to do pixel-perfect object versus pixel-perfect objects. My current setup is a vehicle that picks its frame from some math
    Code:
    //draw rotation of sprite, add half a rotation (180/15) so frame-selection is offset a bit
    draw_sprite(sprite1, floor(((facing_direction+360 + 180/15) mod 360) / 15), x, y);
    This can be skipped because all of this is supposed to be logic before transferring positions and states to the actual rendered product. I can probably update image_angle and do something much simpler to check for collisions.

    All of this is beside the point, and it remains that collision_line() is quirky in the scenario where one of the frames of a precise sprite could be defined by an imprecise rectangle and is not detected properly.
     
  6. Misty

    Misty Member

    Joined:
    Jun 22, 2016
    Posts:
    1,019
    Just use Box2d for top-down racing. However, GM doesnt allow you to iterate through Box2d collision groups per frame, so you will not be able to use bridges or ramps in it. Therefore you may have to learn to use collision_line anyway.

    Just to make sure, the wall object must also set to precise if I remember correct. You said it did already, which is strange. In that case, make sure the sprite mask is set properly. Also make sure your line points are properly defined. Draw a circle where the each line point is to make sure.
     

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