I’m trying to code a helicopter that can tilt, rotate, and pitch. Currently, the tilt and pitch work, but I cannot rotate. I’m using an align rotation that makes the helicopter copy the movement of a test cube, to simulate smoothness. However, when enabled, the test part rotates weirdly, sort of like a magnet. It sticks to either -90 or 90 on the Y rotation, and stays there and does not move. Once the align rotation is disabled, it rotates freely but it is clamped on the -90 → 90 rotation on the Y. I don’t think the script is doing this, but i’m not too sure.
Video showing weird behavior →
Global script →
local heli = script.Parent
local seat = heli.VehicleSeat
local topHinge = heli.TopHinge
local inSeat = false
local prox = seat.ProximityPrompt
local keyEvent = game.ReplicatedStorage.Key
local plr = nil
local cameraEvent = game.ReplicatedStorage.Camera
local topForce = heli.TopForce
local throttleDown = false
local throttleNegativeDown = false
local throttle = 0
local speed = 2000
local maxSpeed = 150000
local percentage = 0
local tiltRightDown = false
local tiltLeftDown = false
local rotateLeftDown = false
local rotateRightDown = false
local mouseDown = false
local health = 100
local rArray = {}
local mouse = nil
for _,v in pairs(heli:GetDescendants()) do
if v:IsA("BasePart") then
table.insert(rArray, v)
end
end
local function smoke(position, getsRemoved)
local exp = game.ReplicatedStorage.VFX.Cloud1BBasic5:Clone()
exp.Parent = workspace
exp.Position = position
exp.FireParticles:Emit(1)
exp.Dist:Play()
if getsRemoved then
coroutine.wrap(function()
wait(4)
exp:Destroy()
end)()
end
end
local function explode(position, breaks, kills)
local exp = game.ReplicatedStorage.VFX.ExplosionBasic5:Clone()
exp.Parent = workspace
exp.Position = position
exp.FireParticles.Enabled = true
exp.SmokeParticles.Enabled = true
coroutine.wrap(function()
task.wait(0.1)
exp.FireParticles.Enabled = false
exp.SmokeParticles.Enabled = false
end)()
exp.Explode:Play()
exp.Dist:Play()
local accuracy = 20
if breaks then
for lat = -80, 80, accuracy do
for lon = 0, 350, accuracy do
local params = RaycastParams.new()
local cf = CFrame.new(position) * CFrame.Angles(math.rad(lon), math.rad(lat), 0)
local raycast = workspace:Raycast(position,cf.LookVector.Unit * 40,params)
if raycast then
if raycast.Instance:IsA("BasePart") then
if raycast.Instance.Name ~= "Terrain" then
raycast.Instance.Anchored = false
end
end
end
end
end
end
if kills then
for lat = -80, 80, accuracy do
for lon = 0, 350, accuracy do
local params = RaycastParams.new()
local cf = CFrame.new(position) * CFrame.Angles(math.rad(lon), math.rad(lat), 0)
local raycast = workspace:Raycast(position,cf.LookVector.Unit * 20,params)
if raycast then
if raycast.Instance:IsA("BasePart") then
if raycast.Instance.Parent then
if raycast.Instance.Parent:FindFirstChildOfClass("Humanoid") then
if script:IsA("Script") then
raycast.Instance.Parent.Humanoid:TakeDamage(100)
else
game.ReplicatedStorage.ShotPlayer:FireServer(raycast.Instance.Parent, 100)
end
end
end
end
end
end
end
end
coroutine.wrap(function()
wait(4)
exp:Destroy()
end)()
end
function getMass(model)
local mass = 0
for i,v in pairs(model:GetDescendants()) do
if(v:IsA("BasePart")) then
mass += v.AssemblyMass
end
end
return mass;
end
game.ReplicatedStorage.Click.OnServerEvent:Connect(function(plr, down)
if down then
mouseDown = true
else
mouseDown = false
end
end)
prox.PromptShown:Connect(function()
print('shown')
end)
prox.PromptHidden:Connect(function()
print('hidden')
end)
prox.PromptButtonHoldBegan:Connect(function()
print('holdbegan')
end)
prox.PromptButtonHoldEnded:Connect(function()
print('holdended')
end)
prox.Triggered:Connect(function(player)
plr = player
plr.PlayerGui.Heli.Enabled = true
cameraEvent:FireClient(plr,true, heli)
seat:Sit(player.Character.Humanoid)
player.Character.Humanoid.JumpHeight = 0
prox.Enabled = false
mouse = player:GetMouse()
for _,v in pairs(player.Character:GetDescendants()) do
if v:IsA("BasePart") then
v.Transparency = 1
v.CanCollide = false
end
if v:IsA("Decal") then
v.Transparency = 1
end
end
task.wait()
inSeat = true
end)
keyEvent.OnServerEvent:Connect(function(player, key, down)
if key == Enum.KeyCode.F then
if down and inSeat and plr and player.Name == plr.Name then
plr.Character.Humanoid.Sit = false
seat:WaitForChild('SeatWeld'):Destroy()
cameraEvent:FireClient(plr,false, nil)
mouse = nil
plr.Character:PivotTo(seat.Attachment.WorldCFrame)
plr.Character.Humanoid.JumpHeight = 7.2
prox.Enabled = true
plr.PlayerGui.Heli.Enabled = false
for _,v in pairs(player.Character:GetDescendants()) do
if v:IsA("BasePart") then
if v.Name ~= "HumanoidRootPart" then
v.Transparency = 0
coroutine.wrap(function()
task.wait(0.5)
v.CanCollide = true
end)()
end
end
if v:IsA("Decal") then
v.Transparency = 0
end
end
cameraEvent:FireClient(plr, false, heli)
inSeat = false
plr = nil
end
end
if key == Enum.KeyCode.LeftShift then
if down then
throttleDown = true
else
throttleDown = false
end
end
if key == Enum.KeyCode.LeftControl then
if down then
throttleNegativeDown = true
else
throttleNegativeDown = false
end
end
if key == Enum.KeyCode.E then
if down then
tiltRightDown = true
else
tiltRightDown = false
end
end
if key == Enum.KeyCode.Q then
if down then
tiltLeftDown = true
else
tiltLeftDown = false
end
end
if key == Enum.KeyCode.D then
if down then
rotateRightDown = true
else
rotateRightDown = false
end
end
if key == Enum.KeyCode.A then
if down then
rotateLeftDown = true
else
rotateLeftDown = false
end
end
end)
while game:GetService('RunService').Heartbeat:Wait() do
if plr then
if mouseDown then
local origin = heli.Main.Shoot.WorldPosition
local dir = heli.Main.CFrame.RightVector * 500
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Blacklist
params.FilterDescendantsInstances = rArray
local tracer = heli.tracer:Clone()
tracer.Parent = heli
tracer.startA.Attachment.WorldPosition = origin
tracer.endA.Attachment.WorldPosition = origin + dir
tracer.startA.light.Transparency = NumberSequence.new(0)
coroutine.wrap(function()
task.wait(0.1)
tracer:Destroy()
end)()
local raycast = workspace:Raycast(origin, dir, params)
if raycast then
explode(raycast.Position, false, true)
end
end
percentage = math.abs(throttle) / maxSpeed
heli.Top.Transparency = percentage
heli.TopDecal.t.Transparency = 1 - percentage
heli.TopDecal.b.Transparency = 1 - percentage
if throttleDown then
if throttle < maxSpeed then
throttle += speed
end
end
if throttleNegativeDown then
if throttle > -maxSpeed then
throttle -= speed
end
end
local rot = workspace.TestPart.Rotation
local x = rot.X
local y = rot.Y
local z = rot.Z
if seat.Throttle > 0.9 then
--W
z = -20
elseif seat.Throttle < -0.9 then
--S
z = 20
else
--none
z = 0
end
if tiltRightDown then
x = 20
elseif tiltLeftDown then
x = -20
else
x = 0
end
if rotateLeftDown then
--heli.LeftForce.Force = Vector3.new(10000,0,0)
--heli.LeftForce.Force = Vector3.new(-10000,0,0)
y += 1
elseif rotateRightDown then
--heli.LeftForce.Force = Vector3.new(-10000,0,0)
--heli.RightForce.Force = Vector3.new(10000,0,0)
y -= 1
else
--heli.LeftForce.Force = Vector3.new(0,0,0)
--heli.RightForce.Force = Vector3.new(0,0,0)
end
local cf1 = CFrame.Angles(math.rad(x),math.rad(y),math.rad(z))
local cf2 = heli.PrimaryPart.CFrame.Rotation
local cf4 = cf2:ToWorldSpace(cf1)
workspace.TestPart.CFrame = cf4
topHinge.AngularVelocity = throttle
heli.RearHinge.AngularVelocity = throttle / 1000
topForce.Force = Vector3.new(workspace.Gravity * heli.PrimaryPart:getMass() * (throttle / maxSpeed) * 1.2,0,0)
end
end
Local script →
local player = game.Players.LocalPlayer
local keyEvent = game.ReplicatedStorage.Key
local uis = game:GetService('UserInputService')
local cameraEvent = game.ReplicatedStorage.Camera
local mouse = player:GetMouse()
mouse.Button1Down:Connect(function()
game.ReplicatedStorage.Click:FireServer(true)
end)
mouse.Button1Up:Connect(function()
game.ReplicatedStorage.Click:FireServer(false)
end)
cameraEvent.OnClientEvent:Connect(function(inseat, heli)
if inseat then
workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable
workspace.CurrentCamera.CameraSubject = heli
else
workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
workspace.CurrentCamera.CameraSubject = player.Character.Humanoid
end
end)
uis.InputBegan:Connect(function(key, down)
keyEvent:FireServer(key.KeyCode, true)
end)
uis.InputEnded:Connect(function(key, down)
keyEvent:FireServer(key.KeyCode, false)
end)
Current setup →

