Tween:Cancel() it's not working properly

I’m making a fidget spinner, and apparently when I do Tween:Cancel() it doesn’t cancel, it just keeps going and kind of gets stuck.

I don’t know if I’m doing something wrong, or it’s a Roblox Studio problem.

Code:

-- SERVICES
local TweenService = game:GetService("TweenService")
-- VARIABLES
local ListenerTool: Tool = script.Parent
local ToolAnimation: Animation = ListenerTool:WaitForChild("Animation") :: Animation
local ToolHandle: Part = ListenerTool:WaitForChild("Handle") :: Part

local AnimationTrack: AnimationTrack?

local WeldCFrameValue: CFrameValue = script:WaitForChild("WeldCFrame") :: CFrameValue

local WeldsFolder: Folder = ToolHandle:WaitForChild("Welds") :: Folder
local ControllerWeld: Weld = WeldsFolder:WaitForChild("Weld") :: Weld

local Debounce: boolean = true

local LastWeldTween: Tween?
-- SOURCE
WeldCFrameValue.Value = ControllerWeld.C1

WeldCFrameValue.Changed:Connect(function(newValue: CFrame)
	ControllerWeld.C1 = newValue
end)

ListenerTool.Activated:Connect(function()
	if Debounce == true then
		Debounce = false
		
		local PlayerCharacter: Model = ListenerTool.Parent :: Model
		local PlayerHumanoid: Humanoid = PlayerCharacter:WaitForChild("Humanoid") :: Humanoid
		local PlayerAnimator: Animator = PlayerHumanoid:WaitForChild("Animator") :: Animator
		
		AnimationTrack = PlayerAnimator:LoadAnimation(ToolAnimation)
		
		if AnimationTrack then
			AnimationTrack:Play()
			
			task.spawn(function()
				task.wait(0.8)
				
				local SecondStep: number = 1
				
				repeat
					LastWeldTween = TweenService:Create(WeldCFrameValue, TweenInfo.new(
						1,
						Enum.EasingStyle.Linear
						), {
							Value = ControllerWeld.C1 * CFrame.Angles(0, math.rad(-180), 0)
						})
					
					if LastWeldTween then
						LastWeldTween:Play()
					end
					
					task.wait(1)
					
					SecondStep += 1
				until SecondStep == 8
				
				if LastWeldTween then
					LastWeldTween:Cancel()
					LastWeldTween = nil
				end
			end)
			
			AnimationTrack.DidLoop:Connect(function()
				if LastWeldTween then
					LastWeldTween:Cancel()
					LastWeldTween = nil
				end
				
				AnimationTrack:Stop()
				
				AnimationTrack = nil
				Debounce = true
			end)
		end
	end
end)

ListenerTool.Unequipped:Connect(function()
	if AnimationTrack then
		if LastWeldTween then
			LastWeldTween:Cancel()
			LastWeldTween = nil
			
			print("CANCELLED")
		end
		
		AnimationTrack:Stop()
		
		AnimationTrack = nil
		Debounce = true
	end
end)

Video:
https://streamable.com/4drz87

1 Like

I tried using Tween:Pause() and it still doesnt works.
https://cdn.discordapp.com/attachments/417879352110481408/933856676623294494/2022-01-20_17-45-39.mp4

This is because Cancel resets the tween variables.

The documentation.

https://developer.roblox.com/en-us/api-reference/class/Tween

Have you tried using Pause instead?

1 Like

If you found a solution, don’t forget to mark it, even if it something you found. So that other developers with similar queries can find answers.

1 Like

I have not found a solution so far.

I think it only cancels the last tween that is created by the loop, try this

-- SERVICES
local TweenService = game:GetService("TweenService")
-- VARIABLES
local ListenerTool: Tool = script.Parent
local ToolAnimation: Animation = ListenerTool:WaitForChild("Animation") :: Animation
local ToolHandle: Part = ListenerTool:WaitForChild("Handle") :: Part

local WeldCFrameValue: CFrameValue = script:WaitForChild("WeldCFrame") :: CFrameValue

local WeldsFolder: Folder = ToolHandle:WaitForChild("Welds") :: Folder
local ControllerWeld: Weld = WeldsFolder:WaitForChild("Weld") :: Weld

local Debounce: boolean = true

local LastWeldTweens: {TweenBase} = {}
function CancelTweens()
	for _, Tween:TweenBase in pairs(LastWeldTweens) do
		Tween:Cancel()
	end
	table.clear(LastWeldTweens)
	print("CANCELLED")
end

-- SOURCE
WeldCFrameValue.Value = ControllerWeld.C1
WeldCFrameValue.Changed:Connect(function(newValue: CFrame)
	ControllerWeld.C1 = newValue
end)


local AnimationTrack, OldAnimationTrack, DidLoop = nil, nil, nil
ListenerTool.Activated:Connect(function()
	if Debounce == true then
		Debounce = false

		local PlayerCharacter: Model = ListenerTool.Parent :: Model
		local PlayerHumanoid: Humanoid = PlayerCharacter:WaitForChild("Humanoid") :: Humanoid
		local PlayerAnimator: Animator = PlayerHumanoid:WaitForChild("Animator") :: Animator
		
		
		AnimationTrack = PlayerAnimator:LoadAnimation(ToolAnimation)
		if not OldAnimationTrack or OldAnimationTrack ~= AnimationTrack then
			if OldAnimationTrack then	OldAnimationTrack:Stop()	end
			if DidLoop then	DidLoop:Disconnect()	end
			DidLoop, OldAnimationTrack = nil, AnimationTrack
			AnimationTrack:Play()

			task.delay(0.8, function()
				for _ = 1, 8 do
					local Tween = TweenService:Create(WeldCFrameValue, TweenInfo.new(
						1,
						Enum.EasingStyle.Linear
						), {
							Value = ControllerWeld.C1 * CFrame.Angles(0, math.rad(-180), 0)
						})
					Tween:Play()
					table.insert(LastWeldTweens, Tween)
					task.wait(1)
				end

				CancelTweens()
			end)
			
			DidLoop = AnimationTrack.DidLoop:Connect(function()
				if DidLoop then	DidLoop:Disconnect()	end
				AnimationTrack:Stop()
				CancelTweens()
				
				DidLoop, AnimationTrack, OldAnimationTrack = nil
				Debounce = true
			end)
		end
	end
end)

ListenerTool.Unequipped:Connect(function()
	CancelTweens()
	if DidLoop then	DidLoop:Disconnect()	end
	if AnimationTrack then	AnimationTrack:Stop()	end
	AnimationTrack, DidLoop, OldAnimationTrack = nil
	Debounce = true
end)

Still doesn’t works, I think it reproduces the same problem.

I fixed it by not using TweenService, but RunService.

-- SERVICES
local RunService = game:GetService("RunService")
-- VARIABLES
local ListenerTool: Tool = script.Parent
local ToolAnimation: Animation = ListenerTool:WaitForChild("Animation") :: Animation
local ToolHandle: Part = ListenerTool:WaitForChild("Handle") :: Part

local AnimationTrack: AnimationTrack?

local WeldsFolder: Folder = ToolHandle:WaitForChild("Welds") :: Folder
local ControllerWeld: Weld = WeldsFolder:WaitForChild("Weld") :: Weld

local Debounce: boolean = true

local InitialControllerWeldCFrame: CFrame = ControllerWeld.C1
local HeartbeatConnection: RBXScriptConnection?
-- SOURCE
ListenerTool.Activated:Connect(function()
	if Debounce == true then
		Debounce = false
		
		local PlayerCharacter: Model = ListenerTool.Parent :: Model
		local PlayerHumanoid: Humanoid = PlayerCharacter:WaitForChild("Humanoid") :: Humanoid
		local PlayerAnimator: Animator = PlayerHumanoid:WaitForChild("Animator") :: Animator
		
		AnimationTrack = PlayerAnimator:LoadAnimation(ToolAnimation)
		
		if AnimationTrack then
			AnimationTrack:Play()
			
			task.spawn(function()
				task.wait(0.8)
				
				HeartbeatConnection = RunService.Heartbeat:Connect(function(deltaTime: number)
					ControllerWeld.C1 = ControllerWeld.C1 * CFrame.Angles(0, math.rad(15) * deltaTime * 60, 0)
				end)
			end)
			
			AnimationTrack.DidLoop:Connect(function()
				AnimationTrack:Stop()
				
				if HeartbeatConnection then
					HeartbeatConnection:Disconnect()
					ControllerWeld.C1 = InitialControllerWeldCFrame
				end
				
				AnimationTrack = nil
				Debounce = true
			end)
		end
	end
end)

ListenerTool.Unequipped:Connect(function()
	if AnimationTrack then
		AnimationTrack:Stop()
		
		if HeartbeatConnection then
			HeartbeatConnection:Disconnect()
			ControllerWeld.C1 = InitialControllerWeldCFrame
		end
		
		AnimationTrack = nil
		Debounce = true
	end
end)

I haven’t gone through any of the scripts but I fail to see how using RunService over TweenService would fix :Cancel() not working as you intended.

1 Like

I clearly stated that I prefer to use RunService instead of TweenService (in this case), since I didn’t need to add any styling to the motion, etc. And it also prevented me from the problems I was having.