Boat camera sway effect

Hi!

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. :slight_smile:

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)

Glad you figured out the boat swaying :slight_smile:

One way would be to keep track of your “target value” (swayingDirection below) and your “current value” (currentSway below).

Both always stay in the range -1 <= x <= 1.

Every frame, move the current value closer to the target value linearly.

Then use the current value as a multiplier for the sway angle. Optionally use TweenService | Documentation - Roblox Creator Hub to smooth out the movement (SmoothSway does this below).

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)


2 Likes

Hey man! Thanks so much for the help today (and yesterday :laughing: ) I got it working too! (vid below)

1 Like

Nice, how does it look with SmoothSway added (Maybe EasingStyle.Quad and EasingDirection.InOut)?

Like this v

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?