Hi I’m currently making my own PvP Combat game and I was wondering if anyone knows how to have the players stay stunned while still being hit multiple times by another player.
I’m using a module script (That is Server-Sided) to perform this task. This is currently what I have written:
local StunModule = {}
function StunModule:Stun(Character:Instance, Duration: number, StunWalkSpeed: number, StunJumpPower: number)
local Humanoid = Character:WaitForChild("Humanoid")
if Humanoid then
if Humanoid.Health <= 0 then
return
end
else
return
end
local WalkSpeed = Humanoid.WalkSpeed
local JumpPower = Humanoid.JumpPower
task.spawn(function()
Humanoid:SetAttribute("Stunned", true)
Humanoid.WalkSpeed = StunWalkSpeed
Humanoid.JumpPower = StunJumpPower
wait(Duration) --// This is the issue.
Humanoid:SetAttribute("Stunned", false)
Humanoid.WalkSpeed = WalkSpeed
Humanoid.JumpPower = JumpPower
end)
end
return StunModule
The stun works, but the issue is that after the player has been stunned once, the wait function will override the next time a player gets stunned again causing the player to be not stunned and get out of a combo.
How do I make it so that the after the player gets stunned again, the task.spawn function restarts from the beginning and makes the player stunned completely, while also ignoring the wait function?
repeat task.wait(1) Duration -= 1 until Duration <= 0
That way you can just add to the duration, causing a “stacking” effect. You would of course, need to store the duration somewhere else and add to it as a different variable.
Yes, you could use an attribute to keep track of the duration, you just need to accommodate the code to utilize it. You could utilize the :GetAttributeChangedSignal() function too, if you really wanted to. In that case, you could just check if the time is greater than 0 and set their WalkSpeed accordingly.
I had this problem some time ago and found the solution
local StunModule = {}
local StunTimes = {}
local function SetDefaultHumanoidAttributes(Character : Instance)
local Humanoid = Character:FindFirstChild("Humanoid")
Humanoid:SetAttribute("WalkSpeed", Humanoid.WalkSpeed)
Humanoid:SetAttribute("JumpPower", Humanoid.JumpPower)
end
function StunModule:Stun(Character : Model, Duration: number, StunWalkSpeed: number, StunJumpPower: number)
local Humanoid = Character:FindFirstChild("Humanoid")
if not Humanoid or Humanoid.Health <= 0 then return end
local WalkSpeed = Humanoid:GetAttribute("WalkSpeed")
local JumpPower = Humanoid:GetAttribute("JumpPower")
if not WalkSpeed or not JumpPower then
SetDefaultHumanoidAttributes(Character)
WalkSpeed = Humanoid:GetAttribute("WalkSpeed")
JumpPower = Humanoid:GetAttribute("JumpPower")
end
StunTimes[Character] = os.clock()
Humanoid:SetAttribute("Stunned", true)
Humanoid.WalkSpeed = StunWalkSpeed
Humanoid.JumpPower = StunJumpPower
task.delay(Duration, function()
if os.clock() - StunTimes[Character] >= Duration then
Humanoid:SetAttribute("Stunned", false)
Humanoid.WalkSpeed = WalkSpeed
Humanoid.JumpPower = JumpPower
end
end)
end
return StunModule
So the problem is that after waiting, we don’t know if the target was stunned again. To do this, you can use newproxy(), which generates a random but unique value each time it is called. It’s not that much more efficient than math.random() or tick(), but it’s the best option.
There’s a lot of limitations to having a loop to check for stun, such as stun having to be a multiple of how often the stun loop checks and task.wait()/wait() being inneffective at very low delays.
Anyways, here’s the code using newproxy()
StunModule.StunProxy = newproxy() --//Also, you should use a variable in the module instead of an attribute.
function bestunned()
local CurrentProxy = newproxy() --//Declare new proxy.
StunModule.StunProxy = CurrentProxy --//If this function is called again, the module's StunProxy variable will change.
task.spawn(function()
Humanoid:SetAttribute("Stunned", true)
Humanoid.WalkSpeed = StunWalkSpeed
Humanoid.JumpPower = StunJumpPower
task.wait(Duration) --// Use task.wait() instead of wait.
if Module.StunProxy == CurrentProxy then
Humanoid:SetAttribute("Stunned", false)
Humanoid.WalkSpeed = WalkSpeed
Humanoid.JumpPower = JumpPower
end
end)
end
Oh, and compared to AkaNub’s code, this is closer to what you’d see in a fighting game where new stun takes priority over old stun. If someone stunned for 10s is hit at 5 seconds for 1 second of stun, they’ll recover in 1 second, not 5.
I had a similar problem with disabling movement/jumping, so I ended up using integer attributes instead of booleans to prevent the issue of the player being able to move when they shouldn’t.
I also used attributes for offsets and multipliers, to make sure nothing weird happens when increasing/decreasing walkspeed.
Your method seems interesting, however. It might be worthwhile for me to look into using newproxy() if I run into a similar issue for future projects.
It could also potentially work for an attribute system similar to Minecraft’s, where stat modifiers are given unique ids.
Ok I tried using this, but sometimes the player gets stun locked permanently except if you hit them again. How do you fix this and should the script be a local or server script?
This is the module script I put into a folder in ReplicatedStorage:
local StunModule = {}
local CurrentProxy
local function SetDefaultHumanoidAttributes(Character : Instance)
local Humanoid = Character:FindFirstChild("Humanoid")
Humanoid:SetAttribute("WalkSpeed", Humanoid.WalkSpeed)
Humanoid:SetAttribute("JumpPower", Humanoid.JumpPower)
end
function StunModule:Stun(Character : Model, Duration: number, StunWalkSpeed: number, StunJumpPower: number)
local Humanoid = Character:FindFirstChild("Humanoid")
if not Humanoid or Humanoid.Health <= 0 then return end
local NewProxy = newproxy()
CurrentProxy = NewProxy
local WalkSpeed = Humanoid:GetAttribute("WalkSpeed")
local JumpPower = Humanoid:GetAttribute("JumpPower")
if not WalkSpeed or not JumpPower then
SetDefaultHumanoidAttributes(Character)
WalkSpeed = Humanoid:GetAttribute("WalkSpeed")
JumpPower = Humanoid:GetAttribute("JumpPower")
end
task.spawn(function()
Humanoid:SetAttribute("Stunned", true)
Humanoid.AutoJumpEnabled = false
Humanoid.WalkSpeed = StunWalkSpeed
Humanoid.JumpPower = StunJumpPower
task.wait(Duration)
if CurrentProxy == NewProxy then
Humanoid:SetAttribute("Stunned", false)
Humanoid.AutoJumpEnabled = true
Humanoid.WalkSpeed = WalkSpeed
Humanoid.JumpPower = JumpPower
end
end)
end
return StunModule
I use a server script to call in the stun module function that works, but sometimes the one of the players are stunlocked until someone hits them again I dont know why.