TransWikia.com

Trying to understand 3D transforms by making an aircraft control script. How would you implement 3D transforms correctly in this example?

Game Development Asked by pocketonion on March 2, 2021

I’m struggling to understand 3D transforms in Godot. (I know, I know…)

I’m trying my best to implement an aircraft control script, and I’ve gotten myself into gimbal lock hell. My controls work pretty well until the Y direction decides to flip, and now my controls to pull up make the plane go down, etc…

I’ve read the godot 3D transform documentation, but I still find myself looking for an "Aha!" moment.

I figured a good way for me to learn would be to post what code I have and see how others would implement the movement code using transforms correctly.

Thanks for any help in advance.

extends Spatial


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
onready var camera = $Camera
const SPEED = 7
const ROTATE_SPEED = 1.25
const MIN = 0.9
var rx = 0
var ry = 0
var rz = 0
# Called when the node enters the scene tree for the first time.
func _ready():
    pass

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    self.transform.basis = Basis()
    if Input.is_action_pressed("movement_forward"):
        ry -= 1
    if Input.is_action_pressed("movement_backward"):
        ry += 1
    if Input.is_action_pressed("movement_left"):
        rx += 1
    if Input.is_action_pressed("movement_right"):
        rx -= 1
    if Input.is_action_pressed("rotate_left"):
        rz += 1
    if Input.is_action_pressed("rotate_right"):
        rz -= 1
    self.transform.orthonormalized()
    
    self.rotate_z(deg2rad(rz))
    self.rotate_x(deg2rad(ry))
    self.rotate_y(deg2rad(rx))
    self.transform.origin += -self.transform.basis.z * SPEED * delta
```

One Answer

I'm not fluent in Godot, but it looks like you want to do something like this:

var rotationDegreesPerSecond = 90

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    # don't reset to default orientation every frame. Rotate from where we are.
    # self.transform.basis = Basis()


    var rotationStep = deg2rad(delta * rotationDegreesPerSecond)

    if Input.is_action_pressed("movement_forward"):
        self.rotate_object_local(Vector3.RIGHT, -rotationStep)
    if Input.is_action_pressed("movement_backward"):
        self.rotate_object_local(Vector3.RIGHT, rotationStep)
    if Input.is_action_pressed("movement_left"):
        self.rotate_object_local(Vector3.UP, rotationStep)
    if Input.is_action_pressed("movement_right"):
        self.rotate_object_local(Vector3.DOWN, -rotationStep)
    if Input.is_action_pressed("rotate_left"):
        self.rotate_object_local(Vector3.FORWARD, rotationStep)
    if Input.is_action_pressed("rotate_right"):
        self.rotate_object_local(Vector3.FORWARD, -rotationStep)


    self.transform.origin += -self.transform.basis.z * SPEED * delta

Here, instead of building a new rotation from scratch using 3 angle totals each frame, we apply a small rotational increment relative to wherever our local coordinate axes are currently pointing. That means your "pitch up" control is always lifting the plane's nose in the direction the top of the plane is pointing - even if the plane is vertical or upside-down at the time.

There is a risk with this style of control that you start to accumulate unwanted roll, as shown in the animated examples I linked in the comments. Since here you've given the player direct control over their roll, they can simply counter-roll to level themselves back out. But you might also want to implement a little bit of an auto-pilot or self-leveling feature that gently nudges the craft back to upright when the player isn't actively trying to roll it over.

Answered by DMGregory on March 2, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP