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?
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).
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.
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.