Answered by
4 years ago Edited 4 years ago
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:
03 | game.Players.PlayerAdded:Connect( function (plr) |
04 | plr.CharacterAdded:Connect( function () |
05 | local Char = plr.Character |
06 | print ( "character made" ) |
07 | local Humanoid = Char:WaitForChild( "Humanoid" ) |
08 | while Humanoid.Health > 0 do |
10 | local State = Humanoid:GetState() |
12 | local head = plr.Character:WaitForChild( "Head" ) |
13 | local root = plr.Character:WaitForChild( "HumanoidRootPart" ) |
15 | local humRegion = Region 3. new(Vector 3. new(root.Position.X - 0.5 , root.Position.Y - 1 , root.Position.Z - . 5 ), Vector 3. new(root.Position.X +. 5 , root.Position.Y + 1 , root.Position.Z +. 5 ) ):ExpandToGrid( 4 ) |
20 | local material = workspace.Terrain:ReadVoxels(humRegion, 4 ) [ 1 ] [ 1 ] [ 1 ] |
22 | if material = = Enum.Material.Water and plr.Character.Humanoid.FloorMaterial = = Enum.Material.Air and debounce = = false then |
24 | local underwater = true |
25 | while underwater = = true do |
27 | Char.Humanoid:TakeDamage( 5 ) |
28 | humRegion = Region 3. new(Vector 3. new(root.Position.X - 0.5 , root.Position.Y - 1 , root.Position.Z - . 5 ), Vector 3. new(root.Position.X +. 5 , root.Position.Y + 1 , root.Position.Z +. 5 ) ):ExpandToGrid( 4 ) |
30 | material = workspace.Terrain:ReadVoxels(humRegion, 4 ) [ 1 ] [ 1 ] [ 1 ] |
31 | if material ~ = Enum.Material.Water or plr.Character.Humanoid.FloorMaterial ~ = Enum.Material.Air then |
33 | print ( "Not underwater" ) |
(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).
01 | game.Players.PlayerAdded:Connect( function (plr) |
02 | plr.CharacterAdded:Connect( function () |
03 | local Char = plr.Character |
04 | print ( "character made" ) |
05 | local Humanoid = Char:WaitForChild( "Humanoid" ) |
06 | while Humanoid.Health > 0 do |
08 | local State = Humanoid:GetState() |
10 | if State = = Enum.HumanoidStateType.Swimming then |
11 | print ( "Started swimming" ) |
12 | while State = = Enum.HumanoidStateType.Swimming do |
14 | State = Humanoid:GetState() |
15 | Humanoid:TakeDamage( 5 ) |
18 | print ( "No longer swimming" ) |
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.