Need help with syncing camera bobbing effect to footsteps

Hey all! I have two separate scripts, one for controlling the user’s camera and UI, including the camera bobbing, and the other for controlling the walking animation and sounds of the player (I have yet to add an Idle animation). What I want is a way to get the camera to “dip” in time with each footstep sound, as right now the camera bobbing will eventually start to go out of sync with the footsteps, since while the footstep sounds are synced with the animation, the camera bobbing is time-based. I have tweaked the delay time to get as close as possible, yet it still happens, and I can’t find this issue brought up anywhere else on Devforum. I’ll leave my two scripts below so that any ideas provided by you amazing people will be able to work with what I have so far. Thank you! :heart:


Camera Script:

local rs = game:GetService("RunService")
local players = game:GetService("Players")
local player = players.LocalPlayer
local character = players.LocalPlayer.Character
local humanoid = character:WaitForChild("Humanoid")
local camera = game.Workspace.CurrentCamera

player:GetMouse().Icon = "rbxassetid://15163012136"
player.CameraMode = Enum.CameraMode.LockFirstPerson

for i, v in ipairs(character:GetDescendants()) do
	if v.Name ~= "Head" and v:IsA("BasePart") then
		v.LocalTransparencyModifier = 0
	end
end

function updateCamera()
	local currentTime = tick()
	if humanoid.MoveDirection.Magnitude > 0 then
		local bobX = math.cos(currentTime * 4) * 0.25
		local bobY = math.abs(math.sin(currentTime * 4)) * 0.4
		local bob = Vector3.new(bobX, bobY, 0)

		humanoid.CameraOffset = humanoid.CameraOffset:lerp(bob, 0.5)
	else
		humanoid.CameraOffset = humanoid.CameraOffset * 0.75
	end
end
rs.RenderStepped:Connect(updateCamera)

Animate Script:

local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")

local walkAnim = script:WaitForChild("walk")
local idleAnim = script:WaitForChild("idle")
local walkSound = Instance.new("Sound")
walkSound.Parent = character:WaitForChild("LowerTorso")
local walkTrack = animator:LoadAnimation(walkAnim)
local idleTrack = animator:LoadAnimation(idleAnim)
walkSound.SoundId = "rbxassetid://15122418400"
walkSound.PlaybackSpeed = 1.5

while true do
	if not (humanoid.MoveDirection.Magnitude <= 0) then
		walkTrack:Play()
		repeat 
			wait() 
		until humanoid.MoveDirection.Magnitude <= 0
	else
		walkTrack:Stop()
		repeat wait() until not (humanoid.MoveDirection.Magnitude <= 0)
	end
	walkTrack:GetMarkerReachedSignal("step"):Connect(function()
		walkSound:Play()
	end)
	humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()
		if humanoid.FloorMaterial == Enum.Material.Cobblestone then
			walkSound.SoundId = "rbxassetid://15122418400"
		elseif humanoid.FloorMaterial == Enum.Material.Ground or humanoid.FloorMaterial == Enum.Material.Grass then
			walkSound.SoundId = "rbxassetid://15130585264"
		end
	end)
end

Can’t you just move the sound trigger to the bobbing script somehow?

I can’t do that unfortunately as the footstep sound is triggered by the animation itself, as shown in this code snippet below from my Animate script:

walkTrack:GetMarkerReachedSignal("step"):Connect(function()
	walkSound:Play()
end)
1 Like

ahhhhhh alright i see the problem

Firing a BindableEvent when the animation track reached the marker is not a valid option?
I don’t have much experience with animations, but you should be able to fire a function to the camera script.

Example code

under the assumptions that animate and camera are both localscripts
Add a BindableEvent in the ReplicatedStorage named CameraBob.

Animate script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
...
walkTrack:GetMarkerReachedSignal("step"):Connect(function()
		walkSound:Play()
        game.ReplicatedStorage.CameraBob:Fire()
	end)
...

Camera script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
...
game.ReplicatedStorage.CameraBob.Event:Connect(function()
--// add the commands to apply bobbing force
end)

This is how I would tackle the issue, but again, I haven’t tried it yet so I’m unsure if this method will bear any result.

I considered this, but the camera bobbing is calculated using RenderStepped tick being calculated through sine and cosine. If I put the camera bob script into that function, the bobbing animation would only play every time the character steps for only as long as the event is fired which basically means it’s only shifting about a single pixel each time.

Did you ever figure this out? Perhaps if you used springs, you could impulse or set the target of the spring on every keyframe reached event fire. Thats probably what I’m going to try doing.