Use physics. First you'll need to establish this:
1. Hovercraft physics principles
The hovercraft's engines will produce an upwards force of magnitude F
, that is opposite in direction to the gravitational force G
. The vertical component of the sum of all forces acting on the hovercraft at any given time will be:
sum_of_forces.y = G - F
The First Law of Newton says that force equals mass times acceleration. If the hovercraft's mass is m
and the gravitational acceleration is 9.8 [m/s2], then G = 9.8 * m
. As for F
, its acceleration will be variable, so we'll call it f
. Therefore, F = f * m
. Replacing G
and F
in the equation above, we have:
sum_of_forces.y = 9.8 * m - f * m;
sum_of_forces.y = (9.8 - f) * m;
All you care about is the acceleration, which we'll name a
:
a.y = sum_of_forces.y / m
a.y = 9.8 - f
The value of a.y
should be recalculated every time f
changes, or to make things simpler, it should be recalculated on every frame.
The y
component of the hovercraft's velocity will be called v.y
. Speed changes based on acceleration, and since you're recalculating the acceleration on every frame, you'll do the same with the velocity:
v.y = v.y + a.y;
And consequently the position. But you probably knew that already:
y = y + v.y;
2. Accelerating based on distance to the ground
Now let's get to the fun part. The hovercraft's vertical acceleration must vary according to its distance from the ground, right? So if h
is the distance from the hovercraft to the ground, both F
(the upwards force opposed to gravity) and f
(the upwards acceleration) are functions of it. Therefore, our previous equation F = f * m
is now:
F (h) = f (h) * m
In order to keep the hovercraft floating at a constant height IDEAL_HEIGHT
from the ground, F
must be equal or greater to the magnitude of the gravitational force. Therefore, this must be true:
F (IDEAL_HEIGHT) = 9.8 * m
and since F = f * m
, this must be true:
f (IDEAL_HEIGHT) = 9.8
As the hovercraft nears the ground, f
should increase. But to be realistic, we'll want to cap f
at a maximum value of f_max
. And as the hovercraft gets farther away from the ground, it should push less. With that in mind, f(h)
must fulfill these two conditions:
f (0) = f_max;
f (IDEAL_HEIGHT) = 9.8;
f (h > IDEAL_HEIGHT) < 9.8;
The simplest possible solution here is to make f (h)
a linear function of the form:
f (h) = m * h + b
To find the m
and b
factors, we do:
m = (9.8 - f_max) / (IDEAL_HEIGHT - 0) = (9.8 - f_max) / IDEAL_HEIGHT
b = f (0) = f_max
Therefore f(h)
looks like this:
f (h) = h * (9.8 - f_max) / IDEAL_HEIGHT + f_max
In pseudocode:
function f ( h ) {
return max ( 0, h * (9.8 - f_max) / IDEAL_HEIGHT + f_max );
}
(Note that I'm using the max()
function to prevent f
from becoming negative.)
3. Putting it all together
So to put it simply, you should just do this on every frame:
// calculate the distance from the hovercraft to the ground
h = hovercraft.y - ground.y;
// calculate the acceleration
a.y = (9.8 - f(h)) * m; // see definition of f() above
// calculate the speed
v.y = v.y + a.y;
// and the position
y = y + v.y;