Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

How to damage a player when they touch water?

Here is what I have so far:

script:GetPropertyChangedSignal("Parent"):Connect(function()
	if script.Parent:IsA("Model") then
		local plr = game.Players:WaitForChild(script.Parent.Name)
		local rf = script.Parent:WaitForChild("RightFoot")
		local hum = rf.Parent:WaitForChild("Humanoid")
		local db = {}
		rf.Touched:Connect(function(hit)
			if hit.Material == Enum.Material.Water then
				if db[plr] == true then
				else
					db[plr] = true
					hum:TakeDamage(15)
					wait(0.5)
					db[plr] = nil
				end
			end
		end)
	end
end)

It is located in game > StarterPlayer > StarterCharacterScripts. It does not damage the player when they touch water and there are no errors, warnings, etc. Could someone point out what is wrong?

4 comments

0

Can you show how you set up the scripts and where?

0

This is the only script.

0

Is the water terrain? Because if it is just a part, you could have the part not able to collide, and then just add a touched event to that

0

Why do you need to detect when the Script's Parent object gets changed? And why do you need to detect if its parent is a Model??? Why are you retrieving the player by looking for a player with the same name as the character(localplayer exists)??? Water isn't a valid material for parts iirc, and you don't need a debounce array since this is for every individual player.

3 answers

Scripts in StarterScripts are ran after they're parented to player/character, so your event will never fire, so simply remove the event part. Also you can use game.Players:GetPlayerFromCharacter(script.Parent) instead of what you're doing (I'm assuming it's a server script).

1 comment

0

Did not work. I am just going to use a part instead.

There's two ways you can do this. You can use

Region = Region3.new()

or you could check if the characters state is swimming

if Humanoid:GetState() == Enum.HumanoidStateType.Swimming then 
   --Do damage
end

Granted, a region3 would work the best, as the character isnt always swimming if they touch the slightest amount of water.

2 comments

0

I have absolutely no clue what Region3 is.

0

https://developer.roblox.com/en-us/api-reference/datatype/Region3 It's just like an invisible area that is created, and whenever something is inside that area, you can make it do something. So in this example, you can check if a player is in the region, and if they are you deal damage to them

I found the best method for getting players server side (as attempting to damage a humanoid on local side is wrong), is to connect an event to both when the player joins, and they get a character. After that, a constant check is operated 1-5 times a second, checking to see if they are in water.

For the check itself, as mentioned by DarkDanny04, are the region and the humanoid state. To quantify this, I decided to have a longer check whilst not in water, then once in water, the check is decreased so that there is not as much resources used until the player is at the water (you could, just make the loop without a second loop inside, for easier coding). For the region method, you define the region and expand it to the grid that the terrain uses (size of 4x4x4) and then check the voxel. For more information on exactly how reading voxels works, I'd suggest reading this: Terrain:ReadVoxels If it's a water material, it will continue to damage them until the check says it is not. Here's the code for the region checking:

local debounce = false

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function()
		local Char = plr.Character
		print("character made")
		local Humanoid = Char:WaitForChild("Humanoid")
		while Humanoid.Health > 0 do
			wait(0.2)
			local State = Humanoid:GetState()
			
			local head = plr.Character:WaitForChild("Head")
			local root = plr.Character:WaitForChild("HumanoidRootPart")
			
			local humRegion = Region3.new(Vector3.new(root.Position.X - 0.5 , root.Position.Y - 1, root.Position.Z - .5), Vector3.new(root.Position.X +.5  , root.Position.Y +1, root.Position.Z +.5) ):ExpandToGrid(4)
			--print(humRegion.CFrame, root.CFrame)
			--print(humRegion.Size)
			
			
			local material = workspace.Terrain:ReadVoxels(humRegion,4)[1][1][1]
			
			if material == Enum.Material.Water and plr.Character.Humanoid.FloorMaterial == Enum.Material.Air and debounce == false then
				debounce = true
				local underwater = true
				while underwater == true do
					print("Underwater")
					Char.Humanoid:TakeDamage(5)	
					humRegion = Region3.new(Vector3.new(root.Position.X - 0.5 , root.Position.Y - 1, root.Position.Z - .5), Vector3.new(root.Position.X +.5  , root.Position.Y +1, root.Position.Z +.5) ):ExpandToGrid(4)
					
					material = workspace.Terrain:ReadVoxels(humRegion,4)[1][1][1]
					if material ~= Enum.Material.Water or plr.Character.Humanoid.FloorMaterial ~= Enum.Material.Air then
						underwater = false
						print("Not underwater")
					end
					wait(0.1)
				end
				debounce = false
			else
				wait(0.1)
    	    end
		end	
	end)
	
end)

(Please be aware I'm not full adept in terrain and voxels, so that method's code is a little all over the place)

The other method, humanoid:getstate() is a lot more simplistic, but doesn't return positive if the player is standing on land in water. You may want this if you have shallow water on your map as well as the deeper oceans (To get around the problem of stand on the water you want to damage, make it deeper).

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function()
		local Char = plr.Character
		print("character made")
		local Humanoid = Char:WaitForChild("Humanoid")
		while Humanoid.Health > 0 do
			wait(0.2)
			local State = Humanoid:GetState()
			
			if State == Enum.HumanoidStateType.Swimming then
				print("Started swimming")
				while State == Enum.HumanoidStateType.Swimming do
					print("Swimming")
					State = Humanoid:GetState()
					Humanoid:TakeDamage(5)
					wait(0.1)
				end
				print("No longer swimming")
			end
		end
	end)
	
end)

Personally, I'd use the humanoid state for flexibility on shallow water, and simpler code, But it's up to you. Here's an uncopylocked game where you can see it all and just copy either scripts.

Hope this has been helpful.

1 comment

0

I am busy right now so I will try it out in a week or so.

This discussion is preserved as it was. New answers, comments, and votes are closed.