(I’ve been stuck with this problem for ages, so I’ll try to be as clear as possible. Hopefully, I’ll get the solution soon )
HELLO FELLOW DEVELOPERS
I’m working on a custom fish character that should always face forward, even when swimming. However, Roblox’s default swimming behavior tilts characters horizontally when they swim forward, which isn’t suitable for my fish character. I want the fish to maintain a forward-facing orientation at all times while swimming (bear in mind; it can also walk on land)
Illustrations (please forgive my poor drawing skills
):
What I’ve Tried:
I’ve attempted to use AlignOrientation
and LinearVelocity
to control the fish’s swimming behavior and orientation. The goal is to ensure the character maintains its orientation while moving smoothly. However, I’ve encountered several issues:
-
AlignOrientation
just doesn’t work (may have done it wrong lol)
- the character’s movement appears smooth for the local player but not for other playrs
- the character’s orientation updates are sometimes jittery
I also looked for solutions on the devforum, but it seems like i’m the only one encountering this problem…
My Current Code:
(also contains a boost system, but that doesn’t matter)
--// SERVICES //--
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local UIS = game:GetService("UserInputService")
--// PLAYER //--
local player = Players.LocalPlayer
--// VARIABLES //--
local Boost_Key = Enum.KeyCode.LeftShift
local NormalSpeed = 50
local BoostSpeed = 80
local lerpFactor = 0.1
local swimSpeed = NormalSpeed
--// FUNCTIONS //--
local function setupSwimmingControl(character)
local humanoid = character:FindFirstChildOfClass("Humanoid")
local primaryPart = character.PrimaryPart
if not humanoid or not primaryPart then return end
local Bubbles = character.Head.Particle.Bubbles
local isSwimming = false
local isMoving = false
local linearVelocity
local alignOrientation
local currentLookDirection = primaryPart.CFrame.LookVector
local function setupLinearVelocity()
local attachment = Instance.new("Attachment", primaryPart)
linearVelocity = Instance.new("LinearVelocity")
linearVelocity.Name = "SwimVelocity"
linearVelocity.MaxForce = math.huge
linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World
linearVelocity.Attachment0 = attachment
linearVelocity.Parent = primaryPart
alignOrientation = Instance.new("AlignOrientation")
alignOrientation.MaxTorque = math.huge
alignOrientation.Responsiveness = 200 -- Adjust as needed
alignOrientation.Attachment0 = attachment
alignOrientation.Parent = primaryPart
end
local function updateVelocity()
if linearVelocity then
if isSwimming and isMoving then
local moveDirection = humanoid.MoveDirection
linearVelocity.VectorVelocity = moveDirection * swimSpeed
else
linearVelocity.VectorVelocity = Vector3.new(0, 0, 0)
end
end
end
local function updateOrientation()
if isSwimming then
local moveDirection = humanoid.MoveDirection
local targetLookDirection = Vector3.new(moveDirection.X, 0, moveDirection.Z).unit
if isMoving then
currentLookDirection = currentLookDirection:Lerp(targetLookDirection, lerpFactor)
else
currentLookDirection = currentLookDirection:Lerp(primaryPart.CFrame.LookVector, lerpFactor)
end
primaryPart.CFrame = CFrame.new(primaryPart.Position, primaryPart.Position + currentLookDirection)
end
end
humanoid.StateChanged:Connect(function(_, newState)
isSwimming = newState == Enum.HumanoidStateType.Swimming
if isSwimming then
if not linearVelocity then
setupLinearVelocity()
end
else
if linearVelocity then
linearVelocity:Destroy()
alignOrientation:Destroy()
linearVelocity = nil
alignOrientation = nil
end
currentLookDirection = primaryPart.CFrame.LookVector
end
updateVelocity()
end)
humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
isMoving = humanoid.MoveDirection.Magnitude > 0
updateVelocity()
if isSwimming then
updateOrientation()
end
end)
RunService.RenderStepped:Connect(function()
if isSwimming and (isMoving or currentLookDirection.Magnitude > 0.001) then
updateOrientation()
end
Bubbles.Enabled = isSwimming and isMoving
end)
end
local function StartBoosting(input: InputObject, isTyping)
if isTyping then return end
if not Boost_Key then
warn("Please enter a valid KeyCode")
return
end
if input.KeyCode == Boost_Key then
swimSpeed = BoostSpeed
end
end
local function StopBoosting(input: InputObject, isTyping)
if isTyping then return end
if not Boost_Key then
warn("Please enter a valid KeyCode")
return
end
if input.KeyCode == Boost_Key then
swimSpeed = NormalSpeed
end
end
--// SETUP //--
UIS.InputBegan:Connect(StartBoosting)
UIS.InputEnded:Connect(StopBoosting)
player.CharacterAdded:Connect(function(character)
setupSwimmingControl(character)
end)
if player.Character then
setupSwimmingControl(player.Character)
end
Additionally, here is the explorer:
Issues Encountered:
-
Tilting Horizontally: The fish character sometimes tilts horizontally despite using
AlignOrientation
. - Smoothness: The movement is smooth for the local player but appears laggy and jittery for other players.
- Orientation Updates: The orientation updates are abrupt and cause jittering, especially noticeable when starting or stopping movement.
Questions:
- How can I prevent the fish character from tilting horizontally and ensure it always faces forward?
- How can I improve the smoothness of the character’s movement and orientation updates, especially for other players in the game?
I appreciate any insights or suggestions. THANK YOU!