GML Rotation collision (example: top-down car)

NeZvers

Member
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:

Pollux568

Member
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 :)
 
L

Lorenzo Lobos

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

NeZvers

Member
@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.
 
L

Lorenzo Lobos

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

NeZvers

Member
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.
 
L

Lorenzo Lobos

Guest
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;
}
 

Shiek4d5

Member
Hi NeZvers, I am making a space game that uses the keyboard for movement rather than mouse. It is more like your car movement or like the game Tanks.
I am forgetting how to make my ship move in the direction that I am facing. Which function makes a player move in any direction? I know how to make the sprite image turn but not how to make it go in that direction. I know the D&D function for it but none of the tutorials actually show what the GML equivalent is for "Move Free" and the other movement functions. I have been away from GM for a year or so.
My game is collision free except for landing on planets, boarding ships, and bullets. In other words, no solid collisions.
I am using W key for acceleration and D key to decelerate. But I have it set up to keep the ship moving in that direction until the ship is turned or slowed down.
If I have no collisions, I still have to check for collisions, right? That's the only way for the object to move in a direction?
 
Top