I used the default Animate script from Roblox to play my custom animations, and alongside that, I added a local script for handling the sprint, crouch, and crawl animations. Some of the animations also have an event named “Step,” so I can also play a sound for each step. The only problem is that the walk animations overlap, so it detects both keyframe events, thus playing the sound repeatedly
Here’s the code that I made for the sprint, crouch, and crawl
Code
--// Services
local ContextActionService = game:GetService("ContextActionService")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
--// Player
local Player = game.Players.LocalPlayer
local Character = Player.Character
local Humanoid = Character:WaitForChild("Humanoid")
local Animator = Humanoid:WaitForChild("Animator")
--// Character States
local StateFolder = Player:WaitForChild("CharacterState")
local IsMoving = StateFolder:WaitForChild("IsMoving")
local IsSprinting = StateFolder:WaitForChild("IsSprinting")
local IsCrouching = StateFolder:WaitForChild("IsCrouching")
local IsCrawling = StateFolder:WaitForChild("IsCrawling")
--// Walkspeed
local CharRef = Player:WaitForChild("CharacterReferences")
local DefaultSpeed = CharRef:WaitForChild("DefaultSpeed")
local SprintSpeed = CharRef:WaitForChild("SprintSpeeed")
local CrouchSpeed = CharRef:WaitForChild("CrouchSpeed")
local CrawlSpeed = CharRef:WaitForChild("CrawlSpeed")
--// Animations
local SprintAnim = script:WaitForChild("run"):WaitForChild("RunAnim")
local CrouchIdleAnim = script:WaitForChild("crouch"):WaitForChild("CrouchIdleAnim")
local CrouchWalkAnim = script:WaitForChild("crouch"):WaitForChild("CrouchWalkAnim")
local CrawlIdleAnim = script:WaitForChild("crawl"):WaitForChild("CrawlIdleAnim")
local CrawlWalkAnim = script:WaitForChild("crawl"):WaitForChild("CrawlWalkAnim")
local SprintAnimTrack = Animator:LoadAnimation(SprintAnim)
local CrouchIdleAnimTrack = Animator:LoadAnimation(CrouchIdleAnim)
local CrouchWalkAnimTrack = Animator:LoadAnimation(CrouchWalkAnim)
local CrawlIdleAnimTrack = Animator:LoadAnimation(CrawlIdleAnim)
local CrawlWalkAnimTrack = Animator:LoadAnimation(CrawlWalkAnim)
--// Keybinds
local SprintBind = Enum.KeyCode.LeftShift
local CrouchCrawlBind = Enum.KeyCode.C
--// Keybind States
local CrouchCrawlIndex = 0 -- 0 = Standing, 1 = Crouching, 2 = Crawling
local CrouchCrawlDebounce = false
local SprintDown = false
local PressDebounce = false
--// Sprint References
local SprintRef = Player:WaitForChild("SprintReference")
local MaxStamina = SprintRef:WaitForChild("MaxStamina")
local StaminaUsage = SprintRef:WaitForChild("StaminaUsage")
local Stamina = SprintRef:WaitForChild("Stamina")
--// State Handler
UserInputService.InputBegan:Connect(function(input, gp)
if gp then return end
if input.KeyCode == CrouchCrawlBind and PressDebounce == false then
if not CrouchCrawlDebounce then
CrouchCrawlDebounce = true
PressDebounce = true
if CrouchCrawlIndex == 0 then
CrouchCrawlIndex = 1
IsCrouching.Value = true
IsCrawling.Value = false
elseif CrouchCrawlIndex == 1 then
CrouchCrawlIndex = 2
IsCrouching.Value = false
IsCrawling.Value = true
elseif CrouchCrawlIndex == 2 then
CrouchCrawlIndex = 0
IsCrouching.Value = false
IsCrawling.Value = false
end
CrouchCrawlDebounce = false
PressDebounce = false
end
elseif input.KeyCode == SprintBind and PressDebounce == false then
PressDebounce = true
CrouchCrawlIndex = 0
IsCrouching.Value = false
IsCrawling.Value = false
SprintDown = true
IsSprinting.Value = IsMoving.Value
end
end)
UserInputService.InputEnded:Connect(function(input, gp)
if gp then return end
if input.KeyCode == SprintBind then
PressDebounce = false
SprintDown = false
IsSprinting.Value = false
end
end)
RunService.RenderStepped:Connect(function()
local isMovingNow = Humanoid.MoveDirection.Magnitude > 0
IsMoving.Value = isMovingNow
if SprintDown and isMovingNow and Stamina.Value > 0 then
IsSprinting.Value = true
else
IsSprinting.Value = false
end
end)
--// Animations Handler
local function UpdateState()
if IsSprinting.Value then
Humanoid.WalkSpeed = SprintSpeed.Value
CrouchIdleAnimTrack:Stop()
CrouchWalkAnimTrack:Stop()
CrawlIdleAnimTrack:Stop()
CrawlWalkAnimTrack:Stop()
SprintAnimTrack:Play()
return
else
SprintAnimTrack:Stop()
end
CrouchIdleAnimTrack:Stop()
CrouchWalkAnimTrack:Stop()
CrawlIdleAnimTrack:Stop()
CrawlWalkAnimTrack:Stop()
if IsCrouching.Value then
Humanoid.WalkSpeed = CrouchSpeed.Value
if IsMoving.Value then
CrouchWalkAnimTrack:Play()
else
CrouchIdleAnimTrack:Play()
end
elseif IsCrawling.Value then
Humanoid.WalkSpeed = CrawlSpeed.Value
if IsMoving.Value then
CrawlWalkAnimTrack:Play()
else
CrawlIdleAnimTrack:Play()
end
else
Humanoid.WalkSpeed = DefaultSpeed.Value
end
end
for i, State in pairs(StateFolder:GetChildren()) do
if State:IsA("ValueBase") then
State.Changed:Connect(UpdateState)
end
end
--// Sprint Handler
local lastSprint = math.huge
RunService.RenderStepped:Connect(function()
if Stamina.Value < StaminaUsage.Value then
IsSprinting.Value = false
SprintDown = false
end
if IsSprinting.Value == true and IsMoving.Value == true and Stamina.Value > 0 then
Stamina.Value = Stamina.Value - StaminaUsage.Value
lastSprint = tick()
else
if tick() - lastSprint >= 1 and Stamina.Value < MaxStamina.Value then
Stamina.Value = Stamina.Value + StaminaUsage.Value
end
end
end)
--// Footstep Sounds
local LeftSound = script.Left
local RightSound = script.Right
local SoundIndex = 0 -- 0 = left, 1 = right
Humanoid.AnimationPlayed:Connect(function(track)
print(track.Name) --where I found out that the animations are overlaping
end)
the only solution I have in mind is to merge this with the default Animate script, but I dont know where and how to start that