GML Rotation collision (example: top-down car)

Discussion in 'Tutorials' started by NeZvers, Aug 10, 2018.

  1. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    194
    GM Version: Should be universal
    Target Platform: ALL
    Download: N/A (all needed code is there)
    Difficulty: Intermediate
    Last Edited: 2018.08.10

    Short version:
    Rotation after dealing with movement collision. Classic while loop checking but this time rotate image_angle to previous position.

    Off-topic:
    There are plenty tutorials that show how to rotate image but they all doesn't rotate collision box and that's useless when you actually need it.
    I tried to make my own top down 2D GTA car movement and I got pretty nice controlls with satisfying drifting, but as soon as I introduced solid walls... crash every time (actually freeze) since I used classic while loop movement collision and turning car into wall with no movement gives infinity while loop. I couldn't find any tutorials so I started to try box2d physics with somewhat ok movement but collisions felt wonky. I don't know why I couldn't think about this simple solution but now it's here.

    Longer version:

    I'll give SUPER bare bone basic car movement (no drift and and fancy things), but maybe I'll do part 2.
    Code:
    /// CREATE_EVENT
    //for this basic car you can use var in step for hspd and vspd
    hspd=0;      // horizontal speed
    vspd=0;      // vertical speed
    acc=0.2;     // acceleration
    spd=0;       // car speed
    mspd=18;     // max speed
    bspd=0.05;   // breaking speed for lerp
    rspd=2;      // rotation speed for turning
    

    Code:
    /// STEP_EVENT
    // input buttons
    var gas  = keyboard_check(ord("W")) - keyboard_check(ord("S"));
    //left turn is positive since GML angles goes counterclockwise
    var turn = keyboard_check(ord("A")) - keyboard_check(ord("D"));
    
    if(gas!=0) // pressing one of directions
    {
        spd+=acc*gas; // adding acceleration to speed in direction of gas
        spd=clamp(spd, -mspd/2, mspd); // can't go faster than max speed
    }
    else // gas buttons are released
    {
        spd=lerp(spd, 0, bspd); // stopping car
    }
    
    /*
    Initialize variable for turning.
    For drifting you"ll need to do things different there.
    Since this is basic car movement, car angle is controlling
    movement direction.
    */
    var angle=image_angle;
    if(turn!=0) // same as gas - turning button is held
    {
        angle+=rspd*turn; // adding turn in held direction
    }
    
    // for this example hspd & vspd could be var
    hspd=lengthdir_x(spd, angle); // extracting horizontal movement
    vspd=lengthdir_y(spd, angle); // extracting vertical movement
    
    //classic collision, may not be the best and must be carefull since it can freeze the game
    if(place_meeting(x+hspd, y, o_Solid)) // checking collision for next horizontal possition
    {
        while(!place_meeting(x+sign(hspd), y, o_Solid))
        { // do loop while no collision 1 pixel in our H direction
            x+=sign(hspd); // move player by 1 pixel in H direction
        }
        hspd=0; // since we can't move anymore set to 0
    }
    x+=hspd; // move object by hspd amount
    
    // exactly the same as hspd only done for vertical movement
    if(place_meeting(x, y+vspd, o_Solid))
    {
        while(!place_meeting(x, y+sign(vspd), o_Solid))
        {
            y+=sign(vspd);
        }
        vspd=0;
    }
    y+=vspd;
    
    /*
    Since we can check collision only for angle we are now
    we need to save value before rotation.
    */
    var prev_angle = image_angle; // save current angle
    image_angle = angle; // turn object according to controlls
    if(place_meeting(x, y, o_Solid)) // check if we are colliding now
    {
        while(place_meeting(x, y, o_Solid)) // here we do opposite - loop while we are collided
        {
            image_angle+= sign(prev_angle - angle); // turn back by 1 degree in direction of previous angle
        }
    }
    
    // Next is optional and not really worked on properly
    // it's reducing car speed if we have collided
    // and point_distance returns only positive number
    /*
    var dir = point_direction(0, 0, hspd, vspd); // we need direction and don't care from where
    if(abs(angle_difference(image_angle, dir)) < 180) // moving same direction we are turned to
    {
        spd=point_distance(0, 0, hspd, vspd); // we need distance, don't care from where
    }
    else
    {
        spd=-point_distance(0, 0, hspd, vspd); // in case we are moving backwards need to turn distance negative
    }
    */
    

    PS:
    Sorry for my English and I hope it's useful for someone frustrated as I was when searched for a solution.
     
    Last edited: Aug 14, 2018
    TinyGamesLab likes this.
  2. Pollux568

    Pollux568 Member

    Joined:
    Oct 12, 2016
    Posts:
    17
    Hi @NeZvers ,
    I have discovered your movement/collision code just now, I'd like to say a big THANKS to you.
    It's been many months that I try to implement something like yours for my submarine game - tried the physics module, downloaded some collision check scripts, the "buttery movement" thing, it was never really satisfactory.
    So, many many thanks :)
     
    NeZvers 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