Help with local pitch, roll, and yaw

I am making a spaceship system, but my spaceship is responding to world vector instead of local vectors. For example, when facing one way, pitch works normally, but when 90 degrees rotated, it rotates another direction instead of controlling pitch locally. As you can see in the video, the pitch doesnt chang with the yaw.

at first W/S is making the front go up and down. When the spaceship is turned, it makes it go side-to-side

(Ignore the flopping at first, that is just a seperate glitch)

My code:

wait(5)

local UIS = game:GetService("UserInputService") -- for getting user input
local RunService = game:GetService("RunService") -- for updating the spaceship
local spaceship = workspace:WaitForChild("Spaceship") -- the spaceship model
local body = spaceship:WaitForChild("Body") -- the main part of the spaceship
local speed = 0 -- the current speed of the spaceship
local maxSpeed = 100 -- the maximum speed of the spaceship
local acceleration = 10 -- the acceleration rate of the spaceship
local deceleration = 5 -- the deceleration rate of the spaceship
local pitch = 0 -- the current pitch angle of the spaceship
local roll = 0 -- the current roll angle of the spaceship
local yaw = 0 -- the current yaw angle of the spaceship
local pitchSpeed = math.pi / 4 -- the angular speed of pitching
local rollSpeed = math.pi / 4 -- the angular speed of rolling
local yawSpeed = math.pi / 4 -- the angular speed of yawing

-- Check if BodyVelocity and BodyGyro exist, create them if not
local bodyVelocity = body:FindFirstChild("BodyVelocity") or Instance.new("BodyVelocity")
bodyVelocity.Velocity = Vector3.new(0, 0, 0)
bodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
bodyVelocity.Name = "BodyVelocity"
bodyVelocity.Parent = body

local bodyGyro = body:FindFirstChild("BodyGyro") or Instance.new("BodyGyro")
bodyGyro.CFrame = CFrame.new()
bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
bodyGyro.Name = "BodyGyro"
bodyGyro.Parent = body

-- This function updates the speed and position of the spaceship
local function updateMovement(dt)
	-- Check if the spacebar is pressed
	if UIS:IsKeyDown(Enum.KeyCode.X) then
		-- Increase the speed by the acceleration rate
		speed = math.min(speed + acceleration * dt, maxSpeed)
	else
		-- Decrease the speed by the deceleration rate
		speed = math.max(speed - deceleration * dt, 0)
	end
	-- Move the spaceship forward by the speed using BodyVelocity
	local forward = body.CFrame.LookVector -- the forward direction of the spaceship
	bodyVelocity.Velocity = Vector3.new(forward.X * speed, 0, forward.Z * speed)
end

-- This function updates the orientation of the spaceship
local function updateRotation(dt)
	-- Check if the W key is pressed
	if UIS:IsKeyDown(Enum.KeyCode.W) then
		-- Increase the pitch angle by the pitch speed
		pitch = pitch + pitchSpeed * dt
	end
	-- Check if the S key is pressed
	if UIS:IsKeyDown(Enum.KeyCode.S) then
		-- Decrease the pitch angle by the pitch speed
		pitch = pitch - pitchSpeed * dt
	end
	-- Check if the A key is pressed
	if UIS:IsKeyDown(Enum.KeyCode.A) then
		-- Increase the roll angle by the roll speed
		roll = roll + rollSpeed * dt
	end
	-- Check if the D key is pressed
	if UIS:IsKeyDown(Enum.KeyCode.D) then
		-- Decrease the roll angle by the roll speed
		roll = roll - rollSpeed * dt
	end
	-- Check if the Q key is pressed
	if UIS:IsKeyDown(Enum.KeyCode.Q) then
		-- Increase the yaw angle by the yaw speed
		yaw = yaw + yawSpeed * dt
	end
	-- Check if the E key is pressed
	if UIS:IsKeyDown(Enum.KeyCode.E) then
		-- Decrease the yaw angle by the yaw speed
		yaw = yaw - yawSpeed * dt
	end
	-- Apply the rotation to the spaceship using BodyGyro
	bodyGyro.CFrame = CFrame.fromEulerAnglesXYZ(pitch, yaw, roll)
end

-- This function updates the spaceship every frame
local function updateSpaceship(dt)
	updateMovement(dt) -- update the movement
	updateRotation(dt) -- update the rotation
end

-- Connect the update function to the RenderStepped event
RunService.RenderStepped:Connect(updateSpaceship)

2 Likes

I ran into this problem a few years ago when trying to make a Star Wars flight system. It seems really complicated at first, but once you learn Matricies and CFrames, you will realize it actually can be solved quite simply. If you take an existing CFrame, and multiply it by an angular CFrame(CFrame.Angles()), it will rotate it locally. I would recommend saving a CFrame of where the ship is(or grab the CFrame every pick, your choice) and update it accordingly. You also can take a blank CFrame, and multiply each axis with the goal value 1 by 1 to achieve the desired result.

2 Likes

Ok… That sounds good, but I’m not very good with math, so thats why I cant figure this out.I have tried working out your method but I can’t figure it out, could you write some example code for me? That would be very helpful!

2 Likes

Thing is he isn’t using an anchored custom rigid mover, he is using legacy body movers.
I haven’t used legacy movers for a while so bear with me.
Try doing bodyMover.CFrame = CFrame.fromEulerAnglesXYZ(pitch, yaw, roll) * CFrame.lookAt(Vector3.zero, spaceship.CFrame.LookVector) and see if that’ll work?

3 Likes

Hmm, its not quite working. What happens, is that the pitch, roll, and yaw have no definition, they all turn it randomly. Also, I can use the new bodymovers, if thats better.

2 Likes

Still need help here! I am still trying to figure this out.

1 Like

Try using AlignPositions and AlignOrientations. They are newer and more reliable. You can set them up so you have a part in front of the plane that the plane is constantly pulled to and facing. Make sure to set torque to be infinite, velocities to be something a little smaller(maybe like 50-1000, depending on the speeds you want). Once you have that, you can work on the movement side of things. I would just rotate the current CFrame by whatever angle you want CFrame.Angles(Pitch, Yaw, Roll).

1 Like