How can I make a realistic lift for my helicopter?

I am currently working on a helicopter. My goal is to make it realistic, and so, I am currently using a vector force to give the helicopter lift. When the player holds W, the vector force is increased (like raising the collective in a helicopter) and inversely for when the player holds S.

Originally, my issue was that when the vector force was applied to my helicopter, it was constantly accelerating, resulting in very high amounts of velocity. To counter this acceleration, I found this post on drag: How do I limit the velocity of VectorForce? - #20 by dthecoolest

After implementing a drag force into my equation for lift, the result I get is unnatural. Although my speed doesn’t increase infinitely, it takes a long time for the speed to stabilize, and it is impossible for the helicopter to be at 0 speed (i.e. hovering).

Here is a video (I am using a platform instead of a helicopter to facilitate the scripting):


Notice how the speed can never reach zero, even when I set the force to be the exact amount required to counter gravity.

Here is an example of what I’m trying to replicate:


As you can see, the speed of the helicopter reaches 0 within a few seconds.

My question is, how can I make my lift feel more realistic? Is a drag force the right way to go, or is there another method? If drag is the right way to go, how can I tweak it so my helicopter can actually enter a hover state?

Here’s my script:

local UIS = game:GetService("UserInputService")
local localPlayer = game.Players.LocalPlayer
local helicopter = script.Parent:FindFirstChild("Helicopter")
local W,S
local increment = 100

UIS.InputBegan:Connect(function(input, gameProcessed)
	if input.KeyCode == Enum.KeyCode.W then
		W = true
	elseif input.KeyCode == Enum.KeyCode.S then
		S = true
	end
end)

UIS.InputEnded:Connect(function(input, gameProcessed)
	if input.KeyCode == Enum.KeyCode.W then
		W = false
	elseif input.KeyCode == Enum.KeyCode.S then
		S = false
	end
end)

local liftForce = Instance.new("VectorForce")
local attachment = Instance.new("Attachment", helicopter.PrimaryPart)
liftForce.Name = "LiftForce"
liftForce.Attachment0 = attachment
liftForce.Force = Vector3.new()
liftForce.RelativeTo = Enum.ActuatorRelativeTo.World
liftForce.Parent = helicopter.PrimaryPart
liftForce.ApplyAtCenterOfMass = true

local dragForce = Instance.new("VectorForce")
local attachment2 = Instance.new("Attachment", helicopter.PrimaryPart)
dragForce.Name = "DragForce"
dragForce.Attachment0 = attachment2
dragForce.Force = Vector3.new()
dragForce.RelativeTo = Enum.ActuatorRelativeTo.World
dragForce.Parent = helicopter.PrimaryPart
liftForce.ApplyAtCenterOfMass = true

game:GetService("RunService").Heartbeat:Connect(function()
	local velocity = helicopter.PrimaryPart.AssemblyLinearVelocity
	local currentLiftForce = liftForce.Force.Y
	local forceRequiredtoHover = helicopter.PrimaryPart.AssemblyMass * workspace.Gravity

	if W and currentLiftForce < 15000 then
		liftForce.Force = Vector3.new(0, currentLiftForce + increment, 0)
	end
	
	if S  and currentLiftForce > 0 then
		liftForce.Force  = Vector3.new(0, currentLiftForce - increment, 0)
	end
	
	if velocity.Magnitude > 0 then
		dragForce.Force = (velocity.Magnitude^2) * -velocity.Unit * Vector3.new(0,1,0)
	else
		dragForce.Force = Vector3.new()
	end
	
	if not W and not S and currentLiftForce < forceRequiredtoHover + 100 and currentLiftForce > forceRequiredtoHover - 100   then
		liftForce.Force = Vector3.new(0, forceRequiredtoHover, 0)
	end
	
	localPlayer.PlayerGui.ScreenGui:FindFirstChild("Speed indicator").Number.Text = string.format("%.2f", velocity.Magnitude)
	localPlayer.PlayerGui.ScreenGui:FindFirstChild("Lift force indicator").Number.Text = currentLiftForce
end)
1 Like

You should probably use AlignPosition and AlignOrientation for this. Mostly AlignPosition

1 Like

I’ve just watched a video of the MTC Helicopter Gameplay (which is i believe the game that’s in the video of this post) and I MIGHT be wrong… but i think it’s a scripted Physics (using BodyVelocity or Linear velocity)…

Here’s a simple script on how you can calculate the Horizontal and Vertical Force

local HorizontalSpeed = 250
local VerticalSpeed = 250

local Pitch = 23

print("HorizontalSpeed: " .. HorizontalSpeed * math.sin(math.rad(Pitch)) .. " Pitch: " .. Pitch)

print("VerticalSpeed: " .. VerticalSpeed * math.cos(math.rad(Pitch)) .. " Pitch: " .. Pitch)

Output

HorizontalSpeed: 97.682782122318 Pitch: 23
VerticalSpeed: 230.12621336311 Pitch: 23

2 Likes

Hey there thanks for linking my post.

For the problem you can try modifying the drag to be linear instead of squared or even add a flat friction modifier that is constant which will help stabilize.

For an example you can checkout my physics character controller which has a flat friction modifier in the running module script.

It may not be 100% realistic but thats just a qualitative term used to determine if a system feels right or not.

2 Likes

Other people have given more practical solutions, but did you know, Roblox recently introduced Aerodynamics into their Physics Simulation?

And, with it, you can make physically-based helicopters that generate lift through actual, rotating blades!

https://twitter.com/sleitnick/status/1846279420354728311

No VectorForces to be seen! Purely the rotation of parts that are slightly angled.

Obviously, this offers less control to the developer and can be more difficult to wrap your head around than just directly applying a force, which is why I implied it’s less “practical”: Sure, it’s more realistic, but it could just cause more problems for actual Game Development.

1 Like

Just saw that you are using heartbeat, that may cause the issue with a system like manual drag force.

Try using .Stepped instead.