Applying lift to a helicopter

Godot Version

4.4.1

Context

I’m playing around with making a flyable helicopter with lift approximations and I have zero background in game-dev or any other 3D environments beyond sometimes trying my hand at Blender.

The following code is an excerpt from my attempt at approximating lift forces for a helicopter. I’ve tried to include only the relevant parts.

class_name Helicopter
extends RigidBody3D

func _ready() -> void:
	center_of_mass.x = rotor.position.x
	center_of_mass.z = rotor.position.z

func _physics_process(_delta: float) -> void:
	# Proportional engine power
	var power := engine_rpm / engine_rpm_max
	
	# Apply some lift even when collective is at 0
	var lift_coeff = collective / 100 * 0.7 + 0.3
	
	# Approximations
	# Lift is force, F = ma => body.mass * g
	# Neutral lift (hover): 5600 * 9.8 = 54_880 N
	# Lift capacity: Maximum load in kg, 
	# used to get the maximum amount of lift generated when 
	# engine is fully powered and collective fully applied
	_lift = lift_capacity * 9.8 * power * lift_coeff
	
	var thrust := _lift
	var pitch := rotation.z
	var roll := rotation.x
	# Rotate the thrust vector according to pitch and roll
	var tx = -thrust * sin(pitch)
	var ty = thrust * cos(roll) * cos(pitch)
	var tz = thrust * sin(roll) * cos(pitch)
	
	# Apply the lift generated by the rotor
	# Orient the forces to local space and apply lift at the rotor position
	apply_force(Vector3(tx, ty, tz) * transform.basis.y, rotor.position)
	
	# Rotation controls
	var torque := Vector3.ZERO
	if pilot:
		var pitch_axis := Input.get_axis("down", "up")
		var roll_axis := Input.get_axis("left", "right")
		var yaw_axis := Input.get_axis("yaw_left", "yaw_right")
		torque.x += roll_axis * 10
		torque.y += -yaw_axis * 100
		torque.z += -pitch_axis * 50
		
		_rotation = torque * 500
		# This does not feel right
		apply_torque(_rotation.y * transform.basis.y)
		apply_torque(_rotation.x * transform.basis.x)
		apply_torque(_rotation.z * transform.basis.z)

Question

My problem currently is the apply_force function. I’m trying to apply the lift at the rotor, however, as it stands, whenever the helicopter starts moving forward, it starts rolling in just about every direction uncontrollably. At first I thought this might be caused by a misalignment of the center of mass and the upward force, which it partially was, which I remedied in the _ready() function (I think at least).

In essence I suppose my question is what does “position is the offset from the body origin in global coordinates” mean in practise when trying to apply the force in a local space context?

Also any other tips/suggestions/comments in regards to this are welcome.

I have uploaded everything in this project to a git repository in case there is something I’ve neglected to share here.

With a rigid body they perform a uniform density calculation of the collision shape, or shapes, to distribute the mass uniformly.

You can easily target the center of mass by calling apply_central_force. Your position of rotor in the ready function is probably not adequate, but there is not enough information provided about the construction of the body/bodies and the collision shape. But in the simplest sense apply_central_force is probably the fix you need.

But if setting the center of mass works, maybe its fine