I want to create a function that is stoppable. An example would be, if a Attributes Changed function is triggered; it would stop a timer that once the timer is complete, would make the Attribute nil.
Issue
My issue is that I have no idea where to start. I have no idea if a coroutine would be a good way to go about this, plus I have little knowledge on coroutines.
What I’m trying to do
I’m currently attempting to create a tag system. Let me elaborate a bit more on what this tag system would do. When a player is tagged by other player, usually through an attack, the Attacker Attribute will be assigned the Attackers Name. After 10 seconds, unless the Attribute is assigned/Changed event has been triggered, it is to reset to a blank string. This also has to recognize if a player who is already in the Attacker Attribute has attacked the player and keep them in the Attribute for a little bit longer.
Script
game.Players.PlayerAdded:Connect(function(plr)
plr.CharacterAdded:Connect(function(Char)
Char:SetAttribute("Attacker"," ")
Char:GetAttributeChangedSignal("Attacker"):Connect(function()
if Char:GetAttribute("Attacker") ~= " " then
local Num,Change = 0,false
if Num ~= 0 then
Num = 0
end
while Num < 10 do
wait(1)
Num += 1
local CurrentNum = Num
local Table2Print = {CurrentNum,Num}
warn(Table2Print)
if Num < CurrentNum then
break
end
end
if Num == 10 then
Char:SetAttribute("Attacker"," ")
Num = 0
else
Num = 0
end
end
end)
end)
end)
Have you looked into using the ‘:GetAttributeChangedSignal()’ method to detect when the values of an object’s attributes are changed?
local Game = game
Game:SetAttribute("Attribute", math.pi)
local function Function()
print(Game:GetAttribute("Attribute"))
end
Game:GetAttributeChangedSignal("Attribute"):Connect(Function)
for _ = 1, 10 do
Game:SetAttribute("Attribute", math.random())
end
Well, the issue is; I’m technically already doing that in my one version; the issue is, there’s one for every single player and gets triggered at different times for each player. With all the trouble I was having, I figured simply just swapping to a new method would be wiser.
Old Coding, updated the original post to reflect this.
game.Players.PlayerAdded:Connect(function(plr)
plr.CharacterAdded:Connect(function(Char)
Char:SetAttribute("Attacker"," ")
SignalListeners.Listeners[Char] = Char:GetAttributeChangedSignal("Attacker"):Connect(function()
if SignalListeners.Timers[Char] then
SignalListeners.Timers[Char] = nil
end
SignalListeners.Timers[Char] = function(Char)
wait(10)
Char:SetAttribute("Attacker","")
end
SignalListeners.Timers[Char](Char)
end)
end)
end)
This is actually possible now that task.cancel is a thing:
--your custom function
function yourFunction(name)
while task.wait() do
print("Hi", name)
end
end
--creates and runs the thread
function startAsync(f, ...)
local thread = task.spawn(f, ...)
return thread
end
--kills the thread
function stopAsync(thread)
task.cancel(thread)
end
--uses the two processes mentioned above to restart the thread
local thread
function restart(f, ...)
stopAsync(thread)
--remove the 3 lines below, I added them to vizualize the process
print("function stopped!")
task.wait(2)
print("function restarted!")
thread = startAsync(f, ...)
end
thread = startAsync(yourFunction, "david")
task.wait(5) --wait 5 seconds
--restart must be called AFTER defining the thread above
restart(yourFunction, "david") --restarts the function
Edit: I wrote a small object to make this process much easier(Module link), it gives the same results with just 4 lines of code:
function func(name)
while task.wait() do
print("Hi", name)
end
end
local ASYNC = require(script.AsyncFunc)
local async = ASYNC.new(func, "david")
async:start()
task.wait(2)
--if parameters are passed inside restart, they override the old function parameters
async:restart("bob")
You are better off using os.clock and a RS.Heartbeat bind.
local Tags : {[Player] : RobloxScriptSignal} = {}
game.repstorage.remote.onserverevent:Connect(function(Player : Player)
if not Tags[Player] then Tags[Player] = os.clock() + 10 end -- seconds end
if Tags[Player] then Tags[Player] = os.clock + 5 end -- add lesser time
end)
RunService.Heartbeat:Connect(function()
for Index : Player, Value : Time in next, Tags do
if Value < os.clock() then
Tags[Index] = nil
end
end)