Water damage script not working well

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

Thanks fro reading!

1 Like

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

3 Likes

Instead of a while loop, you can use Humanoid.Swimming to detect when a character is swimming.

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
1 Like

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)


or easier yet just do

while Humanoid.HumanoidState == Enum.HumanoidStateType.Swimming.Swimming do
-- Do the loop
end

Once the while loop is false it doesn’t turn back on when it’s true.

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.

If you want to make a handler for every player so you don’t have to deal with a lot of scripts lagging your game do:

local players = game:GetService("Players")

players.PlayerAdded:Connect(function(plr)
    plr.CharacterAdded:Connect(function(char)
        char:WaitForChild("Humanoid").Swimming:Connect(function()
            wait(1)
            character:WaitForChild("Humanoid"):TakeDamage(5)
        end)
    end)
end)

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.

1 Like

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.

1 Like

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.

1 Like