Holding animation isn't freezing as intended

I’m trying to create a simple hold and release animation in a tool. So when the player holds F, the hold animation will freeze until the player releases which’ll play the release animation. Everything works except the hold animation occasionally doesn’t freeze and resets. I tried remaking the animation, messing with its priority, and asking in discord servers but I can’t seem to find a solution.

The animation event “End” is on the second-to-last frame of the animation, and both animations have their priority set to Action with Looping disabled

local UIS = game:GetService("UserInputService")

local Player = game.Players.LocalPlayer
local Tool = script.Parent
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local Mouse = Player:GetMouse()

local Equipped = false

local Debounce = false
local Charged = false

local COOLDOWN = 2

local Animator = Character.Humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", Character.Humanoid)
local HoldAnimation = Animator:LoadAnimation(script.hold)
local ReleaseAnimation = Animator:LoadAnimation(script.release) 


Tool.Equipped:Connect(function()
	Equipped = true
end)

Tool.Unequipped:Connect(function()
	Equipped = false
end)

UIS.InputBegan:Connect(function(input, processed)
	if processed or input.KeyCode ~= Enum.KeyCode.F or not Equipped then
		return
	end

	if input.UserInputType == Enum.UserInputType.Keyboard and not processed and not Debounce then
		Debounce = true
		Charged = true
		
		HoldAnimation:Play()
		HoldAnimation:GetMarkerReachedSignal("End"):Connect(function()
			task.wait() --added this because i didn't know what else to do
			HoldAnimation:AdjustSpeed(0)
			print("Hold animation frozen")
		end)
		
		local BG = Instance.new("BodyGyro", Character.HumanoidRootPart)
		BG.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Mouse.Hit.Position)
		BG.MaxTorque = Vector3.new(0, 99999, 0)
		BG.P = 3000
		BG.D = 100
		BG.Name = "Align"

		local BP = Instance.new("BodyPosition", Character.HumanoidRootPart)
		BP.Position = Character.HumanoidRootPart.Position
		BP.MaxForce = Vector3.one * 99999
		BP.P = 3000
		BP.D = 100
		BP.Name = "Position"

		Humanoid.WalkSpeed = 0
		Humanoid.JumpHeight = 0
		
		
		repeat
			BG.CFrame = CFrame.new(Character.HumanoidRootPart.Position, Mouse.Hit.Position)
			task.wait()
		until not Charged or not Equipped

		Humanoid.WalkSpeed = 16
		Humanoid.JumpHeight = 7.2

		BG:Destroy()
		BP:Destroy()
		
		--if Animator then (commenented this out to see if it was the cause but it wasn't)
		--	for _, track in pairs(Animator:GetPlayingAnimationTracks()) do
		--		track:Stop()
		--	end
		--end
		--print("ANIMATION")
		--ReleaseAnimation:Play()
		
		task.wait(COOLDOWN)
		Debounce = false
		
	end
end)

UIS.InputEnded:Connect(function(input, processed)
	
	if Equipped and input.KeyCode == Enum.KeyCode.F then
		Charged = false
	end
	
end)

RobloxStudioBeta_lzna0Z5in6

1 Like

I suspect that the issue is happening due to the fact that you’re creating a new connection each time the player presses their F key, without disconnecting the previous ones

Replacing :Connect with once :Once may potentially solve the problem, as long as it’s guaranteed that the AnimationTrack will always reach the End marker


Try using this script instead:

local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local ACTION_NAME = "HoldAction"
local COOLDOWN = 2

local player = Players.LocalPlayer
local mouse = player:GetMouse()

local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid"):: Humanoid
local rootPart = character.PrimaryPart or character:WaitForChild("HumanoidRootPart"):: BasePart

local animator = humanoid:WaitForChild("Animator"):: Animator
local holdAnimation = animator:LoadAnimation(script:WaitForChild("hold"))
local releaseAnimation = animator:LoadAnimation(script:WaitForChild("release"))

local tool = script.Parent


local connections = {}:: {RBXScriptConnection}
local debounce = false
local instances = {}:: {Instance}


local function onHoldBegan()
	local attachment = Instance.new("Attachment")
	attachment.CFrame = CFrame.fromEulerAnglesYXZ(0, math.rad(90), 0)
	attachment.Parent = rootPart
	table.insert(instances, attachment)

	local alignOrientation = Instance.new("AlignOrientation") -- Replaces BodyGyro
	alignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
	alignOrientation.AlignType = Enum.AlignType.PrimaryAxisLookAt
	alignOrientation.Attachment0 = attachment
	alignOrientation.MaxTorque = 99999
	alignOrientation.Parent = rootPart
	table.insert(instances, alignOrientation)

	local alignPosition = Instance.new("AlignPosition") -- Replaces BodyPosition
	alignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
	alignPosition.Position = rootPart.Position
	alignPosition.Attachment0 = attachment
	alignPosition.MaxForce = 99999
	alignPosition.Parent = rootPart
	table.insert(instances, alignPosition)

	humanoid.WalkSpeed = 0
	humanoid.JumpHeight = 0

	holdAnimation:Play()
	table.insert(connections, holdAnimation:GetMarkerReachedSignal("End"):Once(function()
		holdAnimation:AdjustSpeed(0)
		print("Hold animation frozen")
	end))

	table.insert(connections, RunService.PreSimulation:Connect(function()
		alignOrientation.LookAtPosition = mouse.Hit.Position
	end))
end

local function onHoldEnded()
	humanoid.WalkSpeed = 16
	humanoid.JumpHeight = 7.2

	for i, connection in connections do
		connection:Disconnect()
		connections[i] = nil
	end

	for i, instance in instances do
		instance:Destroy()
		instances[i] = nil
	end
end

local function onHoldAction(_, userInputState: Enum.UserInputState)
	if userInputState == Enum.UserInputState.Begin then
		if debounce then return end
		debounce = true

		onHoldBegan()

		task.wait(COOLDOWN)
		debounce = false
	elseif userInputState == Enum.UserInputState.End then
		holdAnimation:Stop()
		releaseAnimation:Play()

		onHoldEnded()
	end
end

local function onEquipped()
	ContextActionService:BindAction(ACTION_NAME, onHoldAction, false, Enum.KeyCode.F)
end

local function onUnequipped()
	holdAnimation:Stop()
	releaseAnimation:Stop()

	ContextActionService:UnbindAction(ACTION_NAME)
	onHoldEnded()
end

tool.Equipped:Connect(onEquipped)
tool.Unequipped:Connect(onUnequipped)

It uses AlignOrientation and AlignPosition rather than BodyGyro and BodyPosition (which are deprecated), and properly cleans up the instances and connections :slight_smile::+1:

1 Like

I tried out your code and unfortunately it still occasionally didn’t work, but I found out that it was due to the signal, so simply moving the animation event down a couple frames fixed it. I did apply the changes you’ve given though :slightly_smiling_face: :+1:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.