GML Rotation collision (example: top-down car)

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

  1. NeZvers

    NeZvers Member

    Mar 24, 2018
    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.

    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.
    //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

    /// 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))
    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
        spd=-point_distance(0, 0, hspd, vspd); // in case we are moving backwards need to turn distance negative

    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

    Oct 12, 2016
    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