I have a script that turns all parts named “Water” into swimmable areas like terrain water, but I want to prevent players from being able to swim up or down, so that they will always be swimming on the surface.
I tried forcing the y-axis bodyvelocity to 0 using hum.MoveDirection * hum.WalkSpeed*Vector3.new(1, 0, 1) but it didn’t change anything; the player was able to move up and down like normal.
Is there any solution to this? (I know that bodyvelocity is deprecated but idk how to use linear velocity or whatever else there is)
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local char = script.Parent
local hum = char:WaitForChild("Humanoid")
local hrp = char:WaitForChild("HumanoidRootPart")
local swim
local waterPart = {}
ReplicatedStorage.PlayerReady.OnClientEvent:Connect(function()
for i, part in pairs(Workspace:GetDescendants()) do
if part.Name == "Water" and part:IsA("BasePart") then
table.insert(waterPart, part)
part.Touched:Connect(function() end)
end
end
end)
RunService.Heartbeat:Connect(function()
local isSwimming = 0
local isFloating = 0
for i=1, #waterPart do
local touching = waterPart[i]:GetTouchingParts()
for i=1, #touching do
for _, part in pairs(char:GetDescendants()) do
if part:IsA("BasePart") and touching[i] == part then
isFloating += 1
end
end
if touching[i] == hrp then
isSwimming += 1
break
end
end
end
if isSwimming >= 1 then
if not swim then
swim = Instance.new("BodyVelocity")
swim.Parent = hrp
end
swim.Velocity = hum.MoveDirection * hum.WalkSpeed + Vector3.new(0,4,0)
if hum:GetState() ~= Enum.HumanoidStateType.Swimming then
hum:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
hum:ChangeState(Enum.HumanoidStateType.Swimming)
end
elseif swim and isSwimming == 0 and isFloating >= 1 then
swim.Velocity = hum.MoveDirection * hum.WalkSpeed * Vector3.new(1,0,1)
elseif swim and isSwimming >= 1 then
swim.Velocity = hum.MoveDirection * hum.WalkSpeed
elseif swim and isFloating == 0 then
swim:Destroy()
swim = nil
hum:SetStateEnabled(Enum.HumanoidStateType.GettingUp, true)
end
end)
You can make two fully transparent parts. Name one partA and name the second one partB (make partB non collidable so it can fire an event but the player wouldn’t feel it). Make partB just below the surface and part A a little bit below Part B and script it so once part B is touched part A goes up and pushes the player up and then part A goes back down. Ask me for something u dont get.
This is just a lot of steps that makes it tedious if u dont want that just make a fully transparent part below the surface. If u either do this or the other step make sure all parts are anchored!!! I was just recommending the other thing because in physics there is something called a buoyant force which is an upward for so in real life because you have oxygen in your body (oxygen being highly buoyant) when you try and swim down it pushes you back up.
Just tried this, it messes up the animation bc the arms are colliding with the part. It also prevents players from actually getting into the water since their hrp has to be submerged completely
I think an easier solution would just be to edit the actual velocity of the player when they are moving (but idk how to do that)
Yeah I did this but the part has to be at a certain depth below the player that it’s too low to stop all vertical movement. Anything lower would cause the hrp to not be submerged
(For reference, the pool of water I have is only 4.75 studs tall)
Ok so I tried changing the humanoid’s WalkSpeed to 0 while in water then having the BodyVelocity move the player, with it tracking Humanoid.MoveDirection and just ignoring the Y value. But now the character won’t rotate to lie flat while swimming and will stay upright. The player will also still move slower when the camera is pointed upwards/downwards.
Only solution to the first issue if I take this route is finding a way to manually orient the player based on what direction they’re moving but again idk how to do that lol.
You can use a BodyGyro to force the character to maintain the correct angle while still allowing them to rotate. As for the speed with camera looking down/up, movement is tied to camera by default but you can force it to be tied to the X or Z axis if you want to try that. Otherwise you can just translate whichever inputs are acting to be fully inputted so that ‘partial’ inputs read as ‘full’ inputs. I did this for my build system top-down camera in Castaway and it works well, but does prevent moving slowly by slightly pressing the stick.
I have figured out an extremely simple solution for you after about an hour of messing around with the core roblox movement script.
If you haven’t already, load into a play test and copy the PlayerModule from StarterPlayerScripts, then exit the play test and paste it into StarterPlayerScripts again. When you put a core roblox script into the folder that it loads into, it overwrites the script and allows you to make edits. The only caveat is that if Roblox updates or changes the core script, yours will be unchanged. In this case, it’s probably not an issue and is pretty common practice among Roblox devs. You can always update the core script by copying it and editing it again later on.
Once you have done the above step(s), simply open the ControleModule and go to (ctrl+g) line 342. This function “calculateRawMoveVector” is the handler for calculating the move vector for the character based on their camera orientation. When a character is walking on land, their movement only affects the X and Z axis no matter what angle the camera is facing. However, when swimming, Roblox incoporates the Y axis so that you can swim up and down. We are simply going to comment out this part and have it treat land and water the same way.