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:
    310
    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
    Edwin and TinyGamesLab like 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.
  3. Lorenzo Lobos

    Lorenzo Lobos Member

    Joined:
    Oct 14, 2018
    Posts:
    6
    this is great . i implemented some collision bouncing and its a bit buggy but im sure i can solve it later. but how would i implement a drift using this? every other tutorial tells me to use the in gamemaker physics which are kinda wonky.
     
  4. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    310
    @Lorenzo Lobos for drift you need separate movement direction from car rotation direction. I also once tried physics and the worst thing was what physics supposed to do good - collision, also I made better feeling drift with my own code. Probably I had to do physics bit different, but it gave the car unreal rotation bounce. I'm thinking to try top down car engine bit later again.
    Meanwhile, you can check - Your World from amazing Mike Dailly, there's project for GTA 1/2 engine remake which seems uncomplete.
     
  5. Lorenzo Lobos

    Lorenzo Lobos Member

    Joined:
    Oct 14, 2018
    Posts:
    6
    how would i go about doing this? what do i have to switch out? i read in multiple forums that i have to store the potential energy of the car and combine both the angles of the potential force and the new implied one but i cant figure out the code. it makes no sense to me since what im using (this code ) its a different method. sometimes i see motion_add being used but when i do it i get stuck to walls.
     
  6. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    310
    This was was the solution for collision only.
    I'm assuming you are just started coding, then experiment with just plain driving code tests, you'll know where to put collision part after that.
    I don't remember how I went about movement angle. I have to go through that again but now I have time only for actual projects.
    If I remember right I did something like moving angle went move_angle = approach(move_angle, visual_angle, something_spd); That would be a simplified way.
     
  7. Lorenzo Lobos

    Lorenzo Lobos Member

    Joined:
    Oct 14, 2018
    Posts:
    6
    would it be too much trouble if you could post an example? ive been tryin to do this all day and i cant figure out the drift for the life of me. i tried different examples and i cant find a simple straight answer on how to implement this without using physics or motion_add . im already so commited to this engine cause it has acceleration and working collsion and i already put some cool d3d stuff in it but its the drifting thats driving me insane. where do i put the move_angle? how does it work? do i take something out that interferes with that? i tried adding point direction with angle . multiplying it, while something is off while something is on. outside keyboard events ... etc.

    /// STEP_EVENT
    // input buttons
    gas = keyboard_check(ord("W")) - keyboard_check(ord("S"));
    //left turn is positive since GML angles goes counterclockwise
    turn = keyboard_check(ord("A")) - keyboard_check(ord("D"));
    var angle=image_angle;

    if(gas!=0) // pressing one of directions
    {

    // adding acceleration to speed in direction of gas

    spd+=(acc*2)*gas;
    spd=clamp(spd, -mspd/2, mspd);



    // motion_add(direction,gas*.1)// 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.
    */


    if(turn!=0) // same as gas - turning button is held
    {if (gas!=0){
    angle+=rspd*turn;
    }

    else{
    angle+=(rspd*turn)



    }}

    // 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, oWall)) // checking collision for next horizontal possition
    {
    while(!place_meeting(x+sign(hspd), y, oWall))
    { // do loop while no collision 1 pixel in our H direction
    x+=sign(hspd); // move player by 1 pixel in H direction
    }
    hspd=0;

    spd = -spd/2;
    //angle = (round(angle/ 45) * 45);// since we can't move anymore set to 0
    }

    x+=hspd

    // exactly the same as hspd only done for vertical movement
    if(place_meeting(x, y+vspd, oWall))
    {
    while(!place_meeting(x, y+sign(vspd), oWall))
    {
    y+=sign(vspd);
    }
    vspd=0;

    spd = -spd/2;
    //angle = (round(angle / 45) * 45);
    }

    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, oWall)) // check if we are colliding now
    {
    while(place_meeting(x, y, oWall)) // 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
    }
    }



    if keyboard_check(ord("J"))
    {
    rspd = 6;
    mspd = 2;



    }
    if keyboard_check_released(ord("J"))
    {rspd = 3;
    mspd = 3;}


    if (angle >= 360){
    angle -= 360;
    }

    if (angle < 0){
    angle += 360;
    }
     

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