Alrighty, so, I’ve found a few ways to handle stuns in my game.
Attributes
Every frame, scripts will look for attributes in the player model. If they have this attribute, it stuns them then decreases the value of the attribute by DeltaTime, and if the attribute <= 0, they become no longer stunned.
This seems fair, but for it gets really messy and really hard on keeping track of the attributes after you make the game more complex.
Stun objects
Similar to the attributes, the script will look for any object in the player model labelled “Stunned”.
If theres no objects, then the player will no longer be stunned. (They get deleted overtime via debris)
Tags
Alright, this is the one I’m having trouble with. I honestly can’t figure out a way to implement tags without the stuns overriding eachother. For example, if a player is stunned for 4 seconds, It’ll create a tag then destroy the tag after 4 seconds. But if theres 0.5 seconds left on the tag, and they get stunned for 1 seconds, they stun will get cancelled early.
I genuinely have no idea how to approach stuns in my game. All of them seem kinda… bad and lackluster. So how would you do it?
When a player character spawns, create a Number value called “StunTime” and parent it inside the player character. Then make a script that checks if the Value of the StunTime is above 0. If it is, then the player is stunned. And it’ll decrease by 1 every second until it reaches 0 in which is when the player Stun Stops. (Works with Attributes too!) And when you want to stun the player, simply set the StunTime value to the desired stun length
Attributes seems to be the best option as it is easily accessible from everywhere in client side as well as server side, and it is also easier to manage compared to objects and tags, at least i suppose to.
However there’s no need to check every time frame as it could heavily decrease server perfomances, every 0.1 seconds is enough for this kind of cooldowns.
Here is an exemple of script that could manage them well:
--[[ Roblox Services ]]--
local PlayerService = game:GetService("Players")
--[[ Tables ]]--
local StateAttributes = {"IsStunned", "IsBurning", "IsPoisoned"}
local CurrentCharacters = {}
--------------------
--[[ Local Functions ]]--
local function SetAttributes(NewCharacter)
for _, AttributeName in StateAttributes do
NewCharacter:SetAttribute(AttributeName, 0)
end
end
local function UpdateAttributes(SelectedCharacter)
for AttributeName, AttributeValue in SelectedCharacter:GetAttributes() do
if AttributeValue > 0 then
SelectedCharacter:SetAttribute(AttributeName, AttributeValue - 0.1)
end
end
end
--------------------
--[[ Main Connections ]]--
PlayerService.PlayerAdded:Connect(function(NewPlayer)
NewPlayer.CharacterAdded:Connect(function(NewCharacter)
CurrentCharacters[NewPlayer.UserId] = NewCharacter
SetAttributes(NewCharacter)
end)
end)
PlayerService.PlayerRemoving:Connect(function(OldPlayer)
CurrentCharacters[OldPlayer.UserId] = nil
end)
--[[ Main Loop ]]--
while task.wait(0.1) do
for UserId, Character in CurrentCharacters do
task.spawn(UpdateAttributes, Character)
end
end
I personally make a PlayerClass which holds Data and their State table. I then use a combination of modules which handle stun, ragdolls etc. I then create methods to use on the PlayerClass which centers all my handlers into one object (Ex: I don’t have to require the stunhandler and can instead call the stun method on my player class object.) The state table is just a dictionary with booleans, strings, or numbers as keys and indexes are the state (Ex: Attacking, blocking, stunned, etc.) If you want some code i’ll add it.