Hello! I’m working on a sword system and I’ve run across this bug which is baffling me!
Basically, I have a “Busy” variable that’s script only (The script is a local script.) It prints perfectly fine, as if the busy variable is changing and working. However the function that checks if busy == false plays whether busy == false or true!
THE PROBLEM AREA
script.Parent.Activated:Connect(function() -- SWING
if busy == false then
if swingCD == 1 then
animtrack2:Play()
swingCD = 2
animtrack2.Stopped:Wait()
--busy = false
elseif swingCD == 2 then
animtrack3:Play()
swingCD = 3
animtrack3.Stopped:Wait()
--busy = false
elseif swingCD == 3 then
animtrack4:Play()
swingCD = 1
animtrack4.Stopped:Wait()
--busy = false
end
end
end)
THE WHOLE SCRIPT
--GENERAL
UIS = game:GetService("UserInputService")
local swingCD = 1
busy = true
--ANIM 1: IDLE
local anim = script.Parent.Animations.Idle
local char = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local load = char:WaitForChild("Humanoid"):FindFirstChild("Animator")
local animtrack = load:LoadAnimation(anim)
--ANIM 2: BLOCKING
local anim1 = script.Parent.Animations.Block
local animtrack1 = load:LoadAnimation(anim1)
--ANIM 3: SWING1
local anim2 = script.Parent.Animations.Swing1
local animtrack2 = load:LoadAnimation(anim2)
--ANIM 4: SWING2
local anim3 = script.Parent.Animations.Swing2
local animtrack3 = load:LoadAnimation(anim3)
--ANIM 5: SWING3
local anim4 = script.Parent.Animations.Swing3
local animtrack4 = load:LoadAnimation(anim4)
--------------------------------------------------
script.Parent.Equipped:Connect(function() -- EQUIP IDLE ANIM
animtrack:Play()
end)
script.Parent.Unequipped:Connect(function() -- UNEQUIP STOP IDLE ANIM
animtrack:Stop()
end)
UIS.InputBegan:Connect(function(input, gameProcessedEvent) -- BLOCK START
if busy == false then
if gameProcessedEvent then return end
if UIS:IsKeyDown(Enum.KeyCode.F) then
animtrack1:Play()
busy = true
end
end
end)
UIS.InputEnded:Connect(function(input, gameProcessedEvent) -- BLOCK END
if gameProcessedEvent then return end
if UIS:IsKeyDown(Enum.KeyCode.F) then else
animtrack1:Stop()
busy = false
end
end)
script.Parent.Activated:Connect(function() -- SWING
if busy == false then
if swingCD == 1 then
animtrack2:Play()
swingCD = 2
animtrack2.Stopped:Wait()
--busy = false
elseif swingCD == 2 then
animtrack3:Play()
swingCD = 3
animtrack3.Stopped:Wait()
--busy = false
elseif swingCD == 3 then
animtrack4:Play()
swingCD = 1
animtrack4.Stopped:Wait()
--busy = false
end
end
end)
Some solutions I’ve tried;
Making a boolvalue and basing the if busy == false check on that.
Using a server script to change the boolvalue and using RemoteEvents from the local script (problem script) to the server script.
I’ve also had strange behavior when it comes to using a boolvalue in explorer, namely the value randomly switching between true and false. There is no other script that is effecting the busy value.
Print the busy value before the if to see what it’s supposed to be, with an easily identified name (I know, Output will tell you the line number of the script, but if you have multiple ifs then it’s easier with the name of the function you’re dealing with.
For example in this function:
UIS.InputBegan:Connect(function(input, gameProcessedEvent) -- BLOCK START
print("InputBegan, busy = ", busy)
if busy == false then
--code
Then do the same for all the other functions that check busy. It should tell you where the issue is.
Then while testing, select the busy bool in the Explorer and check the Properties to see what the bool is changing to and compare them.
Hello, I forgot to mention that I’ve already done that and it still prints just fine. It goes busy when it’s supposed to and it goes un-busy when it’s supposed to. I also forgot to mention but I’ve return the value back to being a script-only thing without a bool, though it was showing the same thing.
its possible im not correctly understanding the problem, but my initial thought is that shouldnt busy be set to true after the “if busy == false then” line? And then set it back to false at the end of that sequence?
I haven’t tested this, but I wrote up a quick state machine implementation for this that should help organize your code and avoid bugs like this.
--!strict
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local tool = script.Parent
local animationsContainer = tool:FindFirstChild("Animations")
local localPlayer = Players.LocalPlayer :: Player
local character = localPlayer.Character or localPlayer.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid") :: Humanoid
local animator = humanoid:WaitForChild("Animator") :: Animator
local BLOCK_KEY_CODE = Enum.KeyCode.F
local animationTracks: { [string]: AnimationTrack } = {
Idle = animator:LoadAnimation(animationsContainer.Idle),
Block = animator:LoadAnimation(animationsContainer.Block),
Swing1 = animator:LoadAnimation(animationsContainer.Swing1),
Swing2 = animator:LoadAnimation(animationsContainer.Swing2),
Swing3 = animator:LoadAnimation(animationsContainer.Swing3),
}
type State = string
local states: { [string]: State } = {
Idle = "Idle",
Blocking = "Block",
MidSwing = "MidSwing",
Swung1 = "Swung1",
Swung2 = "Swung2",
}
type Action = string
local actions: { [string]: Action } = {
Block = "Block",
Unblock = "Unblock",
Swing = "Swing",
}
type Transition = () -> nil
local currentState: State = states.Idle
local function doBlock()
animationTracks.Block:Play()
currentState = states.Blocking
end
local function doSwingAsync(swingAnimationTrack: AnimationTrack, nextState: State)
currentState = states.MidSwing
swingAnimationTrack:Play()
swingAnimationTrack.Stopped:Wait()
currentState = nextState
task.delay(1, function()
if currentState == nextState then
currentState = states.Idle
end
end)
end
local transitions: { [Action]: { [State]: Transition } } = {
[actions.Block] = {
[states.Idle] = doBlock,
[states.Swung1] = doBlock,
[states.Swung2] = doBlock,
},
[actions.Unblock] = {
[states.Blocking] = function()
currentState = states.Idle
end,
},
[actions.Swing] = {
[states.Idle] = function()
doSwingAsync(animationTracks.Swing1, states.Swung1)
end,
[states.Swung1] = function()
doSwingAsync(animationTracks.Swing2, states.Swung2)
end,
[states.Swung2] = function()
doSwingAsync(animationTracks.Swing3, states.Idle)
end,
},
}
local function isEquipped()
return tool.Parent == character
end
local function tryAction(action: string)
if not isEquipped() then
return
end
local transition = transitions[action][currentState]
if transition then
transition()
end
end
tool.Equipped:Connect(function()
animationTracks.Idle:Play()
end)
tool.Unequipped:Connect(function()
animationTracks.Idle:Stop()
tryAction(actions.Unblock)
end)
UserInputService.InputBegan:Connect(function(inputObject: InputObject, isProcessed: boolean)
if isProcessed then
return
end
if inputObject.UserInputType == Enum.UserInputType.Keyboard then
if inputObject.KeyCode == BLOCK_KEY_CODE then
tryAction(actions.Block)
end
end
end)
UserInputService.InputEnded:Connect(function(inputObject: InputObject, isProcessed: boolean)
if isProcessed then
return
end
if inputObject.UserInputType == Enum.UserInputType.Keyboard then
if inputObject.KeyCode == BLOCK_KEY_CODE then
tryAction(actions.Unblock)
end
end
end)
tool.Activated:Connect(function()
tryAction(actions.Swing)
end)