Raycast doesn't detect player is in part water

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.
image

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?

Can we see the raycastSettings? And what output did you get when printing the result?

This is raycastSettings:

local raycastSettings = RaycastParams.new()
raycastSettings.FilterType = Enum.RaycastFilterType.Whitelist
raycastSettings.FilterDescendantsInstances = CollectionService:GetTagged("Water")

And for the output, when it prints the water block normally when it’s supposed to until I go too underneath.

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.

1 Like

Thanks for a reply, I just got a question. Will these methods be performance costly if I have events listening on a lot of parts?

Instead of having events listening on each part, why not do it just on the player? And no, it wouldn’t be performance costly.