Hey, this is my first release and one of many to come!
This swimming system allows your player to swim through any part of your choosing, it allows for your own animations for idling and also while actually swimming!
Why is the 2nd argument a string to refer to the water part? Shouldn’t it be the part itself?
I think an interface like this would look good compaired to using 6 parmeters:
local Swimzone = require(game.ReplicatedStorage.Swimzone)
local Zone = Swimzone.new()
-- Interface: Get, Set Methods
Zone:SetMaxSpeed(7)
Zone:SetPart(workspace.Water)
-- Another Interface: Indexing
Zone.MaxSpeed = 7
Zone.Part = workspace.Water
-- Another Interface: Get, Set Methods Chainable
local Zone = Swimzone.new():SetMaxSpeed(7):SetPart(workspace.Water)
print(Zone) --> Swimzone (workspace.Water)
Putting a lot of arguments in a row like that can be hard to read for some people. But then there’s TweenInfo.new that takes 6 arguments… so I don’t know. But I’m still confused about argument 2. Why is argument 2 a string and not a part?
Can’t you just put workspace.Water? Or {workspace.Water1, workspace.Water2}? Or even better, using CollectionService and passing something like "Tag:Water" or just "Water"? Is the string just detecting each part by name?
Took a look at the code and I modified it to work as many people want it.
Code
local player = game.Players.LocalPlayer
local character = player.Character
local root = character.HumanoidRootPart
local humanoid = character.Humanoid
local camera = workspace.CurrentCamera
local debris = game:GetService("Debris")
local params = RaycastParams.new()
params.FilterDescendantsInstances = {character}
params.FilterType = Enum.RaycastFilterType.Blacklist
local swimming = {}
swimming.__index = swimming
function swimming.new(MAX_SPEED, WaterParts, IdleAnimation, ActionAnimation, YLaunch)
local boolValue = Instance.new("BoolValue")
boolValue.Name = "Swimming"
boolValue.Value = false
boolValue.Parent = character
local self = {}
self.MAX_SPEED = MAX_SPEED
self.WaterParts = WaterParts
self.BodyOfWater = nil
self.YLaunch = YLaunch or 50
self.Idle = humanoid:LoadAnimation(IdleAnimation)
self.Action = humanoid:LoadAnimation(ActionAnimation)
game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
local result = workspace:Raycast(root.Position, root.CFrame.UpVector * -3, params)
if result and table.find(self.WaterParts,result.Instance) and not boolValue.Value and result.Instance.CanCollide then
local bp = Instance.new("BodyPosition")
bp.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
bp.P = 1500
bp.D = 300
bp.Parent = root
bp.Position = result.Position - Vector3.new(0,3,0)
local bg = Instance.new("BodyGyro")
bg.MaxTorque = Vector3.new(math.huge,math.huge,math.huge)
bg.P = 1500
bg.D = 300
bg.Parent = root
humanoid.PlatformStand = true
self.BodyOfWater = result.Instance
result.Instance.CanCollide = false
boolValue.Value = true
end
if boolValue.Value then
local bp : BodyPosition = root:FindFirstChild("BodyPosition")
local bg : BodyGyro = root:FindFirstChild("BodyGyro")
if humanoid.MoveDirection .Magnitude == 0 then
if self.Action.IsPlaying then
self.Action:Stop(.5)
end
if self.Idle.IsPlaying == false then
self.Idle:Play(.5)
end
bg.CFrame = camera.CFrame
else
if self.Idle.IsPlaying then
self.Idle:Stop(.5)
end
if self.Action.IsPlaying == false then
self.Action:Play(.5)
end
bp.Position += camera.CFrame.LookVector * self.MAX_SPEED * deltaTime
bg.CFrame = camera.CFrame * CFrame.Angles(-math.rad(90),0,0)
end
if bp.Position.Y >= self.BodyOfWater.Position.Y + self.BodyOfWater.Size.Y / 2 then
swimming.Stop(self,true)
elseif bp.Position.X >= self.BodyOfWater.Position.X + self.BodyOfWater.Size.X / 2 then
swimming.Stop(self)
elseif bp.Position.X <= self.BodyOfWater.Position.X + -self.BodyOfWater.Size.X / 2 then
swimming.Stop(self)
elseif bp.Position.Z >= self.BodyOfWater.Position.Z + self.BodyOfWater.Size.Z / 2 then
swimming.Stop(self)
elseif bp.Position.Z <= self.BodyOfWater.Position.Z + -self.BodyOfWater.Size.Z / 2 then
swimming.Stop(self)
end
end
end)
return setmetatable(self, {})
end
function swimming.Stop(self,isUp)
self.Action:Stop()
self.Idle:Stop()
character.Swimming.Value = false
if root:FindFirstChild("BodyPosition") then
root.BodyPosition:Destroy()
end
if root:FindFirstChild("BodyGyro") then
root.BodyGyro:Destroy()
end
if isUp then
local bv = Instance.new("BodyVelocity")
bv.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
bv.P = 1500
bv.Velocity = root.CFrame.UpVector * self.YLaunch
bv.Parent = root
debris:AddItem(bv,.1)
end
humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
task.spawn(function()
task.wait(.5)
self.BodyOfWater.CanCollide = true
self.BodyOfWater = nil
end)
end
return
Didn’t test if it works since I don’t have all the time and parameters to set up, but let me know if it doesn’t work.