In my game, I have a system for part water. The way I detect that a player is in it is by using a raycast, along with a whitelist of all of my water parts. Here is what that looks like.
local raycastResult = Workspace:Raycast(humanoidRootPart.Position, Vector3.new(0, -3, 0), raycastSettings)
I also have a BodyForce active when the player is “swimming”, and the code for calculating the force of it looks like this.
local function getMassFromModel(model)
local mass = 0
for _, object in ipairs(model:GetDescendants()) do
if object:IsA("BasePart") then
mass += object:GetMass()
end
end
return mass
end
local playerMass = getMassFromModel(character)
local velocity = Vector3.new(0, playerMass * Workspace.Gravity, 0)
(Note: The force is set to 0,0,0 when they’re not swimming, and to velocity when they are)
Now in the image, below the raycast is able to successfully detect that the player is in water and apply the logic.
The problem is that if I go lower, then the raycast won’t detect it. Now, I want to know what is the best way to approach this, what would be the most optimized(which might leave Region3 out of the question), and what would just plain work.
Also, in the case that I have to approach this problem in an entirely different way, would a combination of Region3 + magnitude to reduce the amount of Regions that are being checked work better?
I believe this is because rays only detect surfaces(for example, faces on a MeshPart), not the inside of parts. For this issue, I would use GetTouchingParts or Touched events. Alternatively, you can raycast until you detect water (which will return a point where the ray touched the water), and if the player is under that point, they’re swimming, if they’re above the point, they’ve stopped swimming. Once they stop swimming, raycast until it detects water. Repeat cycle.