Either have barriers, or change the gravity. There are more complex ways, those are the simplest in your case. Does your FPS use custom avatars, and or the classic FPS games method, where you make arms and duplicate them to the player’s camera?
If you know exactly how far your water goes down, you could simply prevent them from going down by checking their depth and applying a small up force.
Something I learned was I could put a region around the character’s head to check if they were submerged in water… which would take from their oxygen and essentially drown them. I think this is a fine case for determining if the player is in water. It can be somewhat expensive though. But knowing you… Haha you should be able to optimize it in no time.
An invisible false floor part could still allow players to be fully underwater if you make the floor low enough to guarantee even the tallest avatars won’t be glitching in and out of running state.
My first thought would be a BodyPosition on the root part, which normally has MaxForce (0,0,0) and Position (0, seaLevel, 0), but when a player’s humanoid is in Swimming state, MaxForce becomes non-zero on the Y axis if the root part Y position is below seaLevel. The seaLevel in this case would be a Y level of the surface of the water, or some small offset from it that you tune for appearance. You’d probably want a small dead zone so that characters can get out of the water smoothly.
This could have the same problems as using custom density to make them very buoyant, in that the character can bob too high and glitch between falling and swimming states at the surface of the water.
I know this is over a week old, but I’ve found another solution and just want to toss my 2 cents in.
At it’s current stage, it’s not the best solution; that being said it’s definitely going in the right direction I believe.
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
repeat wait() until player.Character
local character = player.Character
character.Humanoid.Swimming:Connect(function(speed)
local descendants = character:GetDescendants()
if(speed > 2) then
for index, descendant in pairs(descendants) do
if(descendant.Name ~= "HumanoidRootPart" and descendant:IsA("Part")) then
descendant.Massless = true
end
end
else
for index, descendant in pairs(descendants) do
if(descendant.Name ~= "HumanoidRootPart" and descendant:IsA("Part")) then
descendant.Massless = false
end
end
end
end)
Granted the user can rotate his character, this does not allow him to dive below the water (and continue diving).
Here’s a GIF: https://gyazo.com/71573c527a863294b105829e2139dd5a
As you can see, you can point your character down but it won’t allow you to go below the water.
I’m sure there’s a way to prevent this if you were to give it some thought, I’ll be thinking about it.