Hello devforum, I have this water damage script. The problem is that when I die once it stops working. Basically I start testing and works well. Then I die and try to swim again and I don’t receive damage. No output errors.
Script:
local player = script.Parent.Parent
local character = player.Character or player.CharacterAdded:Wait()
while wait(1) do
if character:WaitForChild("Humanoid"):GetState() == Enum.HumanoidStateType.Swimming then
character:WaitForChild("Humanoid"):TakeDamage(5)
end
end
it is because your setting the character at the start of the script which means when you die and respawn it makes a new character for you setting your character varaible to nil.
One way to fix this is to charcaterAdded event
local player = script.Parent.Parent
local character = player.Character or player.CharacterAdded:Wait()
player.CharacterAdded:Connect(function(char)
character = char
end)
while wait(1) do
if character:WaitForChild("Humanoid"):GetState() == Enum.HumanoidStateType.Swimming then
character:WaitForChild("Humanoid"):TakeDamage(5)
end
end
I didnt test this so you might need to fix syntax errors
Character here will not be updated when the character is changed.
You would want something similar to what I have put below. All it does is check to see if the player already has a character and if it doesn’t then it will automatically change when the event fires. This will keep your script using the players current character.
local character -- Defines character so we don't have 2 locals
if player.Character then
character = player.Character
end
player.CharacterAdded:Connect(function(C))
character = C
end
Okay so what you gotta do is run that script every time the player’s character is added you gotta run it again and stop the while loop if he is not inside the water:
local player = script.Parent.Parent
player.CharacterAdded:Connect(function(character)
while wait(1) and character do
if character:WaitForChild("Humanoid"):GetState() == Enum.HumanoidStateType.Swimming then
character:WaitForChild("Humanoid"):TakeDamage(5)
end
end
end)
That will not work due to it checking the condition once, and if it is false then it moves on. By the way, you added an extra .Swimming. I would also like to mention that there is a Humanoid.Swimming that you can use instead of looping.
well in terms of performance detecting when the player starts swimming and binding it to that while loop would work. Having a constant loop in play wont be great so I would actually change that to a much smaller interval.
Another thing I think I should mention is that the current loop runs on a 1 second cycle which means I could jump in and out of the water to never take damage.
In terms of performance, a loop is not better. You are constantly checking the Humanoid’s state. Where the event will run the function when the player is swimming.
Well using a loop is rather unavoidable and for this kind of use it wont really have an effect on performance.
You can check for when they start swimming and end swimming but overall a loop is still required.
You can detect when they start swimming and then start the while loop. This means that it will only start looping once a player starts swimming.
local char -- Defines character so we don't have 2 locals
if player.Character then
char = player.Character
end
player.CharacterAdded:Connect(function(C)) -- For when Char changes
char = C
end
char:WaitForChild("Humanoid").Swimming.Changed:Connect(function() -- Detects when they start swimming
while Char:WaitForChild("Humanoid").HumanoidState == Enum.HumanoidStateType.Swimming do -- Starts the loop
wait(0.2)
Char:WaitForChild("Humanoid"):TakeDamage(1) -- lower loop interval but same total damage per sec
end
end)
It can be more practical than your average loop and this is only a low memory usage loop anyway. It will need to check the state regardless but this wont cause strain unless you are using it for hundreds of players at once.