Lunar Lander calculating gravity, acceleration and collision in GameMaker

I'm making a little Lunar Lander game as my first foray in to GameMaker, I'm wanting to have the ship land and take off again too. I'm new to scripting and programming in general and I'm having trouble with acceleration, in particular with gravity.

Basically I need to:

• Be constantly pulled downwards to simulate gravity up to a maximum speed (terminal velocity)
• Activate thrusters to accelerate my ship towards its current direction
• Turn the ship left and right, therefore adjusting my current direction
• Land on surfaces (I've been accomplishing the collision by setting my gravity to 0) and then take off again (thereby activating gravity again)

The problem:

• I can't figure out a natural, correct way to accelerate the ship with gravity up to its terminal velocity
• I also can't figure out how to add the ship's thrust to gravity (i.e. if I'm facing downwards and firing the thrusters I should be going faster than if I wasn't firing the thrusters). As gravity is only pulling me down in the y direction and the thrust of the ship could be a force pushing me in any direction (according to my ship's angle) this is tricky (for me...).
• The whole thing doesn't feel like particularly smooth motion

An example of my code is as follows:

direction = image_angle

fallSpeed += grav

if fallSpeed > 2
{
fallSpeed = 2
}

y += fallSpeed

if keyboard_check(ord('W')) and speed < maxSpeed
{
shipThrust += 2/room_speed
}
else
{
shipThrust -= 2/room_speed
}

if shipThrust > 20/room_speed
{
shipThrust = 20/room_speed
}

if shipThrust < 0
{
shipThrust = 0
}

if place_meeting(x,y,oGround)
{
fallSpeed = 0
grav = 0
}
else
{
grav = 0.2
}

if keyboard_check(ord('A'))
{
image_angle += 3
}

if keyboard_check(ord('D'))
{
image_angle -= 3
}

speed = max(speed -0.1,0)


Some of that code is probably (read: clearly...) wrong and I figure I need an overall 'speed' value of the ship that I then affect with my two forces (gravity and thrust) but I can't for the life of me figure out how to do it. Any help is appreciated, thanks! :)

• The only way I can think of smoothly approaching a terminal velocity is by including drag or wind resistance to oppose the other driving forces (gravity/thrusters). This is not trivial but shouldn't be too hard. It would also mean that if you thrusters move the ship downwards the ship would move faster than under gravity alone. If someone knows another way please correct me. Feb 9, 2016 at 9:20
• If this is on the moon, there is no air, and thus no terminal velocity. It is the "velocity at which the resistance due to air molecules hitting the object exactly equals the force of gravity." according to Wikipedia's definition. Dec 11, 2017 at 4:15

I'm unfamiliar with game-maker and its' syntax so I'll leave that part up to you.

This psuedo-code should get you close:

If (W) acceleration++;
If (S) acceleration--;
clamp(acceleration, min, max);
velocity += normalizedDirection * acceleration * deltaTime;
If (!landed) velocity += gravity * deltaTime;
clamp(velocity, min, max);
position += velocity * deltaTime;
if (position.y > 0) //If not on the ground
landed = false; //Take off
else if (!landed) //Otherwise, if we haven't landed yet
{
position.y = 0; //Ignore physics and snap ship to terrain
acceleration = 0; //Cut the engines
velocity = 0; //Thud
landed = true; //Don't apply gravity until we've taken off again
rotation = 0; //Fix bad landings??
}


Gravity is an acceleration in WorldUnits/Second/Second
Velocity is in WorldUnits/Second

You'll also need to wrap the rotation keys in an 'If (!landed)' so you cant turn while 'landed'.

• Once you get this working, you're going to remember why spaceships use so many boosters for liftoff. If the initial burst of take-off acceleration is not sufficiently powerful, the ship will slide horizontally along the ground until you have fully countered gravity. I leave it to you to add a cutoff point at which the engines activate/deactivate. Once the cutoff is reached, begin applying acceleration to velocity.
– Jon
Feb 9, 2016 at 5:02
• Thanks a lot, this sounds sensible. I have been away the last two days which is why I haven't replied, but the answer is much appreciated. I'll try the pseudo code when I get a chance. Feb 11, 2016 at 23:34

As I mentioned in my comment a terminal velocity is a result of drag on an object limiting the maximum velocity. This means that in order to have a smooth approach of the terminal velocity drag needs to be included somewhere in your game (of course this is not strictly physical as a small moon is unlikely to have an atmosphere to cause drag, I am going to ignore this point for now).

This question on the physics stack exchange details how it is possible to include drag (it also includes some Python code detailing how to simulate it). For pseudo code I would suggest,

if(W){
thrusterAcceleration = direction * thrusterPower;
}
else{
thrusterAccleration = (0,0);
}

finalAcceleration =  thrusterAcceleration - gravity
- drag * velocity * (velocity.normalised);

velocity += finalAcceleration * deltaTime;
position += velocicty * deltaTime;


to update your position vector. Note here I have used vectors, i.e. some struct or class with an x and y component. If you require a solution without these I can post some psuedo code later (note the above linked question has a solution with x and y separate).

You may need to play around with the constants drag, gravity and thrusterPower as often what appears good in games is not the actual true values. An example is Super Mario (example stolen from this answer here) which has different value of gravity for different cases;

• When jumping regularly, Mario experienced a gravity of 67.82 m/s^2 (6.9 times Earth gravity). Here he had a push-off velocity of 17.36 m/s.
• When high-jumping, Mario experienced a gravity of 34.79 m/s^2 (3.5 times Earth gravity). Here he had a push-off velocity of 15.21 m/s.
• When falling off a ledge, Mario experienced a gravity of 55.88 m/s^2 (5.7 times Earth gravity).
• As for running, Mario seemed to follow a perfectly constant run velocity pattern (as is expected, really). When walking, he moved at a speed of about 3.7 m/s, and when running, moved at a speed of about 9.1 m/s.

My answer involves the use of GameMaker's Physics Engine, which may not be the right answer for everyone.

To initiate the physics system: 1) check the "use physics" check-box for all relevant object, including the ship and the ground, which can be built from rectangular box(es). 2) check the "use physics" option in all relevant rooms. 3) adjust the gravity to the desired amount in the room setting. 4) assign sprites to all physical objects, and in the object menu, create a suitable physics fixture.

The ways in which the questioner's requirements can be fulfilled:

1)Gravity and terminal velocity: These can be fulfilled first by the automatic acceleration created by the gravity setting. Terminal velocity can be achieved by this code:

if phy_speed_y>10
{
phy_speed_y=10
}


where 10 is the terminal velocity you allow.

2)Thruster: draw your ship with the sprite pointing to the right. Do these in your "w-pressed" event:

NetForce=10
physics_apply_force (x,y,XForce,YForce)


This will apply a force to the ship, or whatever is running this code from its origin point, if you want to be more sophisticated, you can replace the "x" and "y" in the "physics_apply_force" command with a specific point (like the thruster's coordinate)

Without physics: simply add or subtract from your image angle with your key presses, except you need to run this code at the end of every step:

phy_rotation=-image angle


With physics:

physics_apply_torque(10)


where "10" is replaced by the desired amount of torque. I believe negative torque turns you clockwise.

4) Land on surfaces: if you do not have very many objects, in the events for the ship and the ground, add this event: "collision". when you add this, the system will ask you which object do you want the current object to collide with, choose "ship" is you are doing ground, choose "ground" if you are doing ship. Then, add some placeholder scripts in the collision events so game maker doesn't automatically delete them as empty events.

If your ship has the right geometry, it should be possible to make it land like a normal object would. If you want to make sure that it has landed on the proper side, simply check the angle it is pointing at when it lands on the place where you want it to be.

If you are dealing with many colliding objects, create a parent object and add a collision event to it, with itself.

Rather than spell out implementation, I'd like to suggest you view the many open source versions of this on GitHub. Here's a simple one in Python, and you should be able to work out the details to translate to GameMaker...

https://github.com/cp4k/PyLander

You can also just search GitHub for Lunar Lander game code at https://github.com/search?utf8=%E2%9C%93&q=lunar+lander

Also, as I mentioned in a comment, there is no terminal velocity in space - only when there is an atmosphere. If you do want your game to work in an atmosphere, I'd say don't worry about it for version 1. Get it to work without, and then figure out how to add it later.

If you are in general worried about the spacecraft going too fast when accelerating, consider it will just crash soon enough and not get that fast.