Synced Footsteps

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I want the footstep to play when an animation event happens on the current animation.
  2. What is the issue? Include screenshots / videos if possible!
    It isn’t synced and just makes a bunch of footsteps.
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried doing things like: animTrack.KeyframeReached:Connect(function(keyframeName) and animTrack:GetMarkerReachedSignal(“Footstep”):Connect(OnFootStep) but I cant get it to work.

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you! I’m pretty new to scripting so if I overcomplicate things or make lots of mistakes that’s why.

-- local Debris = game:GetService("Debris")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local root = character:WaitForChild("HumanoidRootPart")
local animator = humanoid:WaitForChild("Animator")
local footprintFolder = ReplicatedStorage:WaitForChild("Footprints")

local footsteps = require(script:WaitForChild("Footsteps"))
local lastFootstepSound = nil
local isRunning = false
local canPlayFootstep = true

local function PlayFootstepSound(foot, material)
	if not foot then return end

	local sounds = footsteps.sounds[material]
	if not sounds then return end

	local random = Random.new()
	local soundId = sounds[random:NextInteger(1, #sounds)]

	if soundId and soundId ~= lastFootstepSound then
		lastFootstepSound = soundId
		local sfx = Instance.new("Sound")
		sfx.SoundId = soundId
		sfx.RollOffMaxDistance = 100
		sfx.RollOffMinDistance = 10
		sfx.Volume = footsteps.volume[material] or 0.5
		sfx.Parent = foot
		sfx:Play()
		task.spawn(function()
			sfx.Ended:Wait()
			sfx:Destroy()
		end)
	end
end

local function OnFootStep()
	local floorMaterial = humanoid.FloorMaterial
	local material = footsteps.materialMap[floorMaterial]

	local foot = character:FindFirstChild(isRunning and "RightFoot" or "LeftFoot")
	PlayFootstepSound(foot, material)

	if material then
		local footprint = footprintFolder:FindFirstChild(material)
		if footprint then
			footprint = footprint:Clone()
			footprint:PivotTo(foot.CFrame * CFrame.new(0, -footprint.PrimaryPart.Size.Y, 0))
			footprint.Parent = workspace
			Debris:AddItem(footprint, footsteps.decay[material] or 3)
		end
	end
end

local function ConnectAnimationEvents()
	local animTracks = animator:GetPlayingAnimationTracks()
	if #animTracks > 0 then
		for _, animTrack in ipairs(animTracks) do
			animTrack:GetMarkerReachedSignal("Footstep"):Connect(OnFootStep)
		end
	end
end

local function PlayFootstep()
	canPlayFootstep = true
end

RunService.Heartbeat:Connect(function()
	ConnectAnimationEvents()

	if humanoid.FloorMaterial ~= Enum.Material.Air and canPlayFootstep then
		canPlayFootstep = false
		task.delay(0.1, PlayFootstep)
	end
end)
1 Like

this only works if you named the keyframe. perhaps thats why?
some reading i found on this

I did name it, but I had the wrong name in the script. Unfortunately the footsteps are still spammed.

sorry for the delay, but im back now :sweat_smile:

animTrack.KeyframeReached:Connect(function(keyframeName) runs every keyframe, use an if statement to only catch the footstep keyframes you want

idk if you still need help since I am replying almost half a year later, but there’s not an indicated solution so here’s my guess on why this bug is occurring

I didn’t look too deeply into your script, but the footstep sounds are most likely playing multiple times per footstep because you are connecting multiple GetMarkerReachedSignal() events, meaning when a footstep occurs, multiple events fire, thus multiple footstep sounds are played. I suggest adding a debounce variable that keeps track of when the event is connected. Remember that each time a character dies, events connected to them are disconnected, so you have to make sure they are being reconnected.