How to do auto-leveling for arcade-style airplane combat ala Rogue Squadron 3d?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By OriginalAGP

I would like to auto-level my airplane every so often on a given axis. The best illustration of this is in the 1998 game Rogue Squadron. I’m moving the ship forward by calling move_and_collide(Vector3), for whatever that’s worth.

Watch this gameplay video and see how the x-wing is always self-correcting:

You probably need to provide more illustration (videos, images…)

Dlean Jeans | 2019-07-17 11:40

I just did, thanks.

OriginalAGP | 2019-07-17 17:31

:bust_in_silhouette: Reply From: Zylann

I dealt with this a few times, and the theory I had was the following:
You need to compute what would be the ideal angle you want your plane to be. Usually, you want to get rid of roll (rotation around Z). Then, take the current angle, compute the difference, and apply it as a torque force. Over multiple frames, this should end up stabilizing the plane closer and closer to its ideal angle. You can also customize how strong that force is by multiplying it by some factor.
When I say “angle” here, it can either be a single axis, or the whole rotation (through a quaternion). There are multiple ways to do it, each with their own results.

In my project I used RigidBody so I called add_torque(): PhysicsDirectBodyState — Godot Engine (3.1) documentation in English, which adds an angular force to the body.

I can’t share this code here, but I have an old, more simplistic version of it online which had the feature: (although it doesnt use physics at all and loopings dont work due to gimbal lock).

I’m not sure what it would be for KinematicBody.

Another approach is to fake it entirely so it’s only a visual trick applied locally just on the mesh and the camera :wink:

I changed it to RigidBody and tried your code directly. Plane moves forward for a while and then, invariably, it falls, even with gravity scaled down to .05 and the plane pointed up. And still, it doesn’t level completely.

I’d be fine with “faking it,” I just down know how to do it…

OriginalAGP | 2019-07-18 20:37

Keep in mind the code I linked was on a Spatial, it was not meant for RigidBody. I’m also not sure if it still works by the time, but I linked it anyways to give an idea on the kind of operations you might need.

Zylann | 2019-07-18 20:39

I applied the script to the ship. The RigidBody is its parent. Is that not how it’s done?

OriginalAGP | 2019-07-18 22:42

Not at all. The script I wrote was the root of the plane and wasn’t faking anything. If you use a RigidBody, you must use its functions instead to add forces to it. That means you can’t just copy/paste my code, but perhaps find some calculations that might be useful to you. At least make sure to understand how such a system works, then find how to do each step.

For faking it, it might look a bit worse but it’s simpler. You’d basically move your plane, not rotate it. Rotation would only be applied on visuals every frame, and you could have a roll variable used to set the Z rotation once other rotations got applied. When turning, you increase roll, and when you stop turning, you decrease it. I haven’t done this kind of faking before though.

first set rotation around global Y, then rotate around the local Z axis.

# Set the two lookat angles (you could use look_at as well?)
set_rotation(Vector3(rotation_x, rotation_y, 0))
# Apply roll
rotate_object_local(Vector3(0, 0, -1), roll)

Then for roll, something like this in _fixed_process:

# Pseudocode!
var max_roll = PI / 4.0
if moving left:
	# Increase roll to the left
	roll = clamp(roll + delta * PI, -max_roll, max_roll)
elif moving right:
	# Increase roll to the right
	roll = clamp(roll - delta * PI, -max_roll, max_roll)
	# Dampen roll
	roll = lerp(roll, 0.0, delta)

However this is just an idea for faking, I haven’t covered looking up and down, you’ll have to tinker with a solution yourself.

Zylann | 2019-07-18 23:24