I’m having some trouble coming up with a way to create a camera sway effect for my ship. At the moment, everything is setup on my camera correctly. But I want it to have a sway effect when turning the boat. I tried implementing a BodyGyro but it kept getting deleted when I put it inside the camera?
Current boat effect (No sway)
Boat effect with hardcoded camera sway to the left
My code is below. Wondering how I could go about this? I was looking around and found some methods but none of them seemed to work. Any advice would be helpful.
local function topDownFollowShip()
if player.Character then
camera.Focus = player.Character.HumanoidRootPart.CFrame
local playerPosition = player.Character.HumanoidRootPart.Position
local playerOrientation = player.Character.HumanoidRootPart.Orientation
local rotatedCFrame = CFrame.Angles(0, math.rad(playerOrientation.Y), 0)
rotatedCFrame = CFrame.new(playerPosition) * rotatedCFrame
camera.CFrame = rotatedCFrame:ToWorldSpace(CFrame.new(CAMERA_OFFSET))
camera.CFrame = CFrame.new(camera.CFrame.Position, playerPosition)
end
end
local function onRenderStep()
topDownFollowShip()
end
runService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value, onRenderStep)
Something like this (untested but shows the principle):
local swayingDirection = 0 -- will be -1 if only turning left, 1 if turning right
local currentSway = 0 -- approaches swayingDirection every frame
local SWAY_TIME = 1 -- how many seconds to finish sway animation from idle
local SWAY_AMOUNT = math.rad(45) -- radians to sway
local function UpdateSway(dt)
local swayingDirection = 0
-- NOTE would need to have a turningLeft variable or some other way to set swayingDirection
if turningLeft then swayingDirection += -1 end
if turningRight then swayingDirection += 1 end
currentSway += swayingDirection * dt / SWAY_TIME
-- clamp to [-1, 1]
if currentSway < -1 then currentSway = -1 end
if currentSway > 1 then currentSway = 1 end
end
--optional function to apply tween
local function SmoothSway(sway)
local sign = 0
if sway < 0 then sign = -1 end
elseif sway > = then sign = 1 end
-- apply tween on [0, 1] absolute value
local smooth = game:GetService("TweenService"):GetValue(math.abs(currentSway), Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
-- then flip it back the right way
return smooth * sign
end
local function topDownFollowShip(dt)
UpdateSway()
if player.Character then
camera.Focus = player.Character.HumanoidRootPart.CFrame
local playerPosition = player.Character.HumanoidRootPart.Position
local playerOrientation = player.Character.HumanoidRootPart.Orientation
local rotatedCFrame = CFrame.Angles(0, math.rad(playerOrientation.Y), 0)
-- apply sway
rotatedCFrame = CFrame.new(playerPosition) * rotatedCFrame * CFrame.Angles(0, SmoothSway(currentSway) * SWAY_AMOUNT, 0)
camera.CFrame = rotatedCFrame:ToWorldSpace(CFrame.new(CAMERA_OFFSET))
camera.CFrame = CFrame.new(camera.CFrame.Position, playerPosition)
end
end
local function onRenderStep(dt)
topDownFollowShip(dt)
end
runService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value, onRenderStep)
I was using linear in the first video because some of the easing styles had kind of a weird jerk to them that I didn’t like. Quad starts off slow then speeds up when turning and feels a little awkward to use yk?