I need help with a drowning script

No, that wouldn’t happen. If the player gets out the water while the for loop is still running, it will call return, ending the function and not allowing the while loop to run.

Not needed for any more variables (unless you add the little last drown effect I stated - this is only for fluidity when running), essentially when you use an IF statement your checking if something exists or is false:

local false_arg = false
local nil_arg = nil
local true_arg = true
local obj_arg = tick()

if false_arg then return end -- As its false.
if nil_arg then return end -- As nothing exists

if true_arg then return end -- As its true.
if obj_arg then return end -- As something exists in that memory pointer.

Checking if an object exists is great especially when using datastore :smile:

1 Like

Why does the character not heal after drowning?

What do you mean by that? If the player steps out the water before dying, Roblox’s default “Health” script should slowly heal the player.

You could use tick() to check if 30 seconds have passed to deal damage after that time has passed.

The roblox “Health” script is not healing the character but it usually does.

I have made an example for you in a localscript of how I would do this. Currently I do not think that subtracting health through a local script replicates to the server actually happens, which means if you want a multiplayer compatible script, this has to be done server side.

I use Humanoid:GetState() which returns the current state of the humanoid to see if you are still swimming, if you are not swimming the timer in the water resets and will continue from 30 if you are back into the water again.

The localscript example:

repeat wait() until game.Players.LocalPlayer.Character

local PS = game:GetService("Players")
local LP = PS.LocalPlayer
local Character = LP.Character
local Humanoid = Character:WaitForChild("Humanoid")
local Drowning = false

local DrownCount = 0

function HumanoidSwam(Old, State)
	if State == Enum.HumanoidStateType.Swimming then
		if Drowning == false then
			Drowning = true
			local StartTick = tick()
		
			DrownCount = 30
			while DrownCount > 0 do
				DrownCount = DrownCount - 1
				print(DrownCount)
				if Humanoid:GetState() ~= Enum.HumanoidStateType.Swimming then
					Drowning = false
					return
				end
				wait(1)
			end
		
			if DrownCount == 0 then
				while Humanoid:GetState() == Enum.HumanoidStateType.Swimming do
					Humanoid:TakeDamage(5)
					wait(5)
				end
			end
			Drowning = false
		end
	end
end

Humanoid.StateChanged:Connect(HumanoidSwam)

Did this help?

2 Likes

Nvm. I put it in the wrong type of script.

I am doing this for a multiplayer game. I do not know if this would work in one.

It’s a problem with your code. You don’t have a timer.


Humanoid.StateChanged:Connect(function (oldState, newState)
	if newState == Enum.HumanoidStateType.Swimming then
		print("Swim")
		Swimming = true
	elseif oldState == Enum.HumanoidStateType.Swimming and newState ~= Enum.HumanoidStateType.Jumping then
		print("No swim")
		Swimming = false
	elseif oldState ~= Enum.HumanoidStateType.Swimming and oldState ~= newState then
		print("No swim")
		Swimming = false
	end

	local firstTick = tick()
	while Swimming do
		wait(1)
		if tick() - firstTick >= 30 then
			Humanoid:TakeDamage(30 / Humanoid.MaxHealth) -- 0skarian said this
		end
	end
end)

So anything else your stuck on that we can help with?

  • If your player isn’t automatically healing then rename any scripts named “Health” in StarterCharacterScripts that way it doesn’t override the core.

I accidentally put it in the wrong script. Two of the answers worked here but I used yours because it damaged the player more equally.

1 Like

If you want this to be multiplayer compatible, it is essential to handle it server side in order to have it replicate on both ends.

I have converted my example into a server script, that will do everything as before, it has the drown damage and cooldown between each hit as a variable as well.

To test it, simply open output so you can view the timer and try to swim around in water.

wait()

local PS = game:GetService("Players")
local Drowning = false

local DrownCount = 0

local DrownDamage = 10
local DrownCooldown = 2


PS.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		local Humanoid = Character:WaitForChild("Humanoid")
		
		Humanoid.StateChanged:Connect(function(Old, State)
			if State == Enum.HumanoidStateType.Swimming then
				if Drowning == false then
					Drowning = true
					local StartTick = tick()
		
					DrownCount = 30
					while DrownCount > 0 do
						DrownCount = DrownCount - 1
						print(DrownCount)
						if Humanoid:GetState() ~= Enum.HumanoidStateType.Swimming then
							Drowning = false
							return
						end
						wait(1)
					end
		
					if DrownCount == 0 then
						while Humanoid:GetState() == Enum.HumanoidStateType.Swimming do
							Humanoid:TakeDamage(DrownDamage)
							wait(DrownCooldown)
						end
					end
					Drowning = false
				end
			end
		end)
	end)
end)

Hope this helped.

1 Like

I will test it. 30 Characters

It does not work. You do not have to fix it because the thing is solved.

Yes, it does. You are probably not using the correct script for it, as I have stated this is for a normal script, not localscript and this one above will replicate to the server unlike the others.

I decided to reply to you with a different method since everyone seems to be using the humanoid state only, maybe I could open the doors for ReadVoxels since nobody uses them for some reason when they’re really nice. (maybe for your use case it doesn’t really matter but still)

I used a server script. eeeeee

How do you merge this script with the drowning script? The one I am currently using has some glitches.

On the server you loop through all the players, check if their humanoids floor material is air, if so do what the script does else they’re not drowning.