So basically, I’m trying to make a footstep script that detects when a new animation is played, and if that animation is a walk or sprint, it’ll hook the sound effects to that playing animation track. And if the walk is already playing, then the player starts sprinting, it should rehook to the correct animation track.
This system worked consistently before I added new materials. Now, when I redid some parts of the script, it worked, to say the least. For some reason, .AnimationPlayed and track.Stopped seem to work really unreliably. I added some print statements at the start of each and they just seem to, not run sometimes? Sometimes the sound just stops playing after I unsprint and keep walking (couldn’t get footage of that sadly), and sometimes the sound is hooked to the walk animation, when the sprint animation is playing. I also discovered that if I spam new animations in general, it will stop the sounds.
(Note: The walk animation has less priority than the sprint, so they both play at the same time, but the sprint plays over the walk.)
^ (The footsteps syncing to the walk animation while I’m running at 0:06)
Here are my scripts: (they may not be the best systems so excuse me
)
Client Side: (detecting movements and base materials)
local runtime = game:GetService('RunService')
--script.Parent:WaitForChild('FootstepSounds').Parent = sounds
repeat wait() until script.Parent:FindFirstChild("Humanoid") and script.Parent.HumanoidRootPart:FindFirstChild("FootstepSounds")
local materials = script.Parent:WaitForChild("HumanoidRootPart"):WaitForChild('FootstepSounds')
local plr = game.Players.LocalPlayer
repeat wait() until plr.Character
local char = plr.Character
local hrp = char:WaitForChild("HumanoidRootPart")
local hum = char:WaitForChild("Humanoid")
local walking
local prevWalkSpeed = nil
hum.Running:connect(function(speed)
if speed > hum.WalkSpeed/2 then
walking = true
else
walking = false
end
end)
function getMaterial()
local floormat = hum.FloorMaterial
if not floormat then floormat = 'Air' end
local matstring = string.split(tostring(floormat),'Enum.Material.')[2]
local material = matstring
return material
end
local prevMat
runtime.Heartbeat:connect(function()
if walking then
local material = getMaterial()
if not materials:FindFirstChild(material) then
return
end
local materialSound = materials[material]
local ws = tonumber(hum.WalkSpeed)
if ws ~= prevWalkSpeed or materialSound.Name ~= prevMat then
prevWalkSpeed = ws
prevMat = materialSound.Name
--print(ws, prevWalkSpeed)
game.ReplicatedStorage.Events.Footsteps:FireServer(materialSound, char, ws)
end
else
prevWalkSpeed = nil
lastFiredMat = nil
end
end)
Server Side: (handling sounds themselves and changing materials if needed)
rs.Events.Footsteps.OnServerEvent:Connect(function(plr, sound, char, walkspeed)
if not sound then return end
if not char then char = plr:WaitForChild("Character") end
local hum = char:WaitForChild("Humanoid")
local velocity = hum.RootPart.Velocity.Magnitude
local materialSound
if sound:IsA("Attachment") then
if animConnection then
animConnection:Disconnect()
animConnection = nil
end
if animStopConnection then
animStopConnection:Disconnect()
animStopConnection = nil
end
task.spawn(function()
local function hookTrack(track)
-- disconnect previous
if connectionMain then
connectionMain:Disconnect()
connectionMain = nil
end
if connectionL then
connectionL:Disconnect()
connectionL = nil
end
if connectionR then
connectionR:Disconnect()
connectionR = nil
end
if track == nil then return end
connectionMain = track:GetMarkerReachedSignal("Footstep"):Connect(function()
local materialSound = sound:FindFirstChild(tostring(math.random(1, #sound:GetChildren())))
-- print(materialSound.Parent)
if materialSound and hum.FloorMaterial ~= Enum.Material.Air then
if sound.Name ~= hum.FloorMaterial.Name then
materialSound = char.HumanoidRootPart.FootstepSounds[hum.FloorMaterial.Name]:FindFirstChild(tostring(math.random(1, #char.HumanoidRootPart.FootstepSounds[hum.FloorMaterial.Name]:GetChildren())))
end
materialSound:Play()
end
end)
connectionL = track:GetMarkerReachedSignal("FootstepL"):Connect(function()
task.spawn(function()
if hum.FloorMaterial ~= Enum.Material.Air then
for _, v in pairs(char["Left Leg"].Footstep:GetChildren()) do
if v:IsA("ParticleEmitter") then
wait()
v:Emit(5)
end
end
end
end)
end)
connectionR = track:GetMarkerReachedSignal("FootstepR"):Connect(function()
task.spawn(function()
if hum.FloorMaterial ~= Enum.Material.Air then
for _, v in pairs(char["Right Leg"].Footstep:GetChildren()) do
if v:IsA("ParticleEmitter") then
wait()
v:Emit(5)
end
end
end
end)
end)
end
animConnection = hum.AnimationPlayed:Connect(function(track)
if track.Animation.AnimationId == char.Animations.Walk.AnimationId --[[if new track is the walk anim]] or track.Animation.AnimationId == char.Animations.Sprint.AnimationId --[[if new track is the sprint anim]] then
hookTrack(track)
end
animStopConnection = track.Stopped:Connect(function()
for i, newTrack in hum:GetPlayingAnimationTracks() do
if (newTrack.Animation.AnimationId == char.Animations.Walk.AnimationId and track.Animation.AnimationId == char.Animations.Sprint.AnimationId) --[[if new track is the walk anim and old track is the sprint]] or (track.Animation.AnimationId == char.Animations.Walk.AnimationId and newTrack.Animation.AnimationId == char.Animations.Sprint.AnimationId) --[[old track is the walk anim and the new track is the sprint]] then
--override the previous
hookTrack(newTrack)
break
else
hookTrack()
end
end
end)
end)
end)
end
end)