You could probably use a BodyVelocity with its Velocity property set to (0, 0, 0) to simulate no gravity, and you could apply a VectorForce to move the player, as well as fiddling with some humanoid states.
So you’re asking for a system that sets your state to Swimming?
That’s fairly easy to do, but can be a bit performance intensive if not handled correctly
Consider looking into Humanoid:ChangeState() as this allows you to arbitrarily set a humanoid’s state
local Sea = workspace.Sea --Directory of the water part
--
local RS = game:GetService("RunService")
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local Root = Character:WaitForChild("HumanoidRootPart")
local Swim
Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
if Root.Position.Y < Sea.Position.Y then
if not Swim then
Swim = Instance.new("BodyVelocity")
Swim.Parent = Root
end
Swim.Velocity = Humanoid.MoveDirection * Humanoid.WalkSpeed
if Humanoid:GetState() ~= Enum.HumanoidStateType.Swimming then
Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
end
elseif Swim then
Swim:Destroy()
end
end)
The issue was so simple. Every time I set the Humanoid state type to Swimming, it got set to GettingUp immediately after. Here’s the finished code to prevent future scripters from struggling with this:
local Sea = workspace.Sea --Directory of the water part
--
local RS = game:GetService("RunService")
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local Root = Character:WaitForChild("HumanoidRootPart")
local Swim
RS.Heartbeat:Connect(function()
if Root.Position.Y < Sea.Position.Y - Root.Size.Y / 2 then
if not Swim then
Swim = Instance.new("BodyVelocity")
Swim.Parent = Root
end
Swim.Velocity = Humanoid.MoveDirection * Humanoid.WalkSpeed + Vector3.new(0,4,0)
if Humanoid:GetState() ~= Enum.HumanoidStateType.Swimming then
Humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
end
elseif Swim and Root.Position.Y < Sea.Position.Y then
Swim.Velocity = Humanoid.MoveDirection * Humanoid.WalkSpeed
elseif Swim then
Swim:Destroy()
Swim = nil
Humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, true)
end
end)
Is there a way I could put this inside of a part script instead of startercharacterscripts? I’m having problems just having it in SCS and would rather just have it in a part. Especially since I am going to have many of them.
I can’t think of a good way of going about that, as swimming is an individual action of each character, just like walking or jumping. I don’t think you should have any kind of problem putting stuff in character scripts, so my recommendation to you is to get that fixed instead.
The code I wrote is very basic. The part is considered “sea level”, which means the player will be able to swim anywhere under the part’s Y coordinate. The whole purpose of the script is to create an infinite sea, something that terrain didn’t allow and came nowhere near in performance. However, for your purpose, the script can be modified by using the ZonePlus module. What you would do is remove the parts that use the “water part” and make use of the “localPlayerEntered” event of ZonePlus.
Do you have any guesses why the swim state stops working completely after the character dies once?
-- original script by aorda!!
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character
if not character or not character.Parent then
character = player.CharacterAdded:Wait()
end
local Humanoid = character:WaitForChild("Humanoid")
local Root = character:WaitForChild("HumanoidRootPart")
local Swim
local Zone = require(game:GetService("ReplicatedStorage").Zone)
local container = game:GetService("Workspace").Testwater
local zone = Zone.new(container)
zone.localPlayerEntered:Connect(function()
if not Swim then
Swim = Instance.new("BodyVelocity")
Swim.Parent = Root
print("swim has been placed")
end
Swim.Velocity = Humanoid.MoveDirection * Humanoid.WalkSpeed + Vector3.new(0,5,0)
if Humanoid:GetState() ~= Enum.HumanoidStateType.Swimming then
print("change state")
Humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
Humanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, false)
Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
end
end)
zone.localPlayerExited:Connect(function()
Swim.Velocity = Humanoid.MoveDirection * Humanoid.WalkSpeed
Swim:Destroy()
Swim = nil
print("swim nil!!")
Humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, true)
end)
Where is this local script? If it’s on starterplayerscripts maybe you can change to startercharacterscripts, if this doesnt works you could put an event that updates the character variable if the player died.
Hey I tried to remake your script but instead, we try to find the “Sea” part in the workspace and can be located thanks to an attribute boolean called “YES”. But it doesnt seem to work, do you any idea?
local Sea
for _, child in pairs(workspace:GetChildren()) do
if child.Name == "Sea" and child:FindFirstChild("YES") then
Sea = child
break
end
end
local RS = game:GetService("RunService")
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local Root = Character:WaitForChild("HumanoidRootPart")
local Swim
Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
if Sea and Root.Position.Y < Sea.Position.Y then
if not Swim then
Swim = Instance.new("BodyVelocity")
Swim.Parent = Root
end
Swim.Velocity = Humanoid.MoveDirection * Humanoid.WalkSpeed
if Humanoid:GetState() ~= Enum.HumanoidStateType.Swimming then
Humanoid:ChangeState(Enum.HumanoidStateType.Swimming)
end
elseif Swim then
Swim:Destroy()
end
end)
Well, it looks like you are looking for the child called “YES” under the Sea part, which I think does not exist as you mentioned it as an attribute, not an object. You can use Instance:GetAttribute method to achieve precisely what you want. Still, I would suggest having an ObjectValue object in a set directory pointing to the sea part to avoid looking for it using a loop for every player.