Modular Swimming System

Un no not at all, its literally for the raycast so it knows which part is water and which isnt

you can take a look at the code, its rather simple really

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.

There is already a different module that has existed for a while that accomplishes this and more called SwimmablePart.

Im confused what exactly did you modify?

Uh I made sure to scour the forums for any swimming systems that may have already been released i didnt find anything, could you link it?

I modified where the raycast check would happen, and the self var with the parameteter.

I think that just takes up more memory then just checking a string to be honest

For sure, the whole code has memory losses here and there. My mistake was that I made another variable instead of using the parameter. One of your mistakes was using a BoolValue instead of an Attribute.

Alright ill keep that in mind for future release, thank you.

Wait what makes attributes better than boolvalues?

Attributes esentially store a few less things which can free a little memory, while also looking clean from Value messes. It cannot store Objects, though.

1 Like

High performance water: Swimmable part 2.0 - Resources / Community Resources - DevForum | Roblox

2 Likes

Hello, cool module! I’m from the “backwards” post with dot product anyways, I’ve wanted to recommend something for your module (MAX_SPEED : number, WaterName : string, IdleAnimation : Animation, ActionAnimation : Animation, YLaunch : number) With colon " : " so it easier to know what’s what when you are creating so it’s easier for people to know what to type in for a second I thought "Max speed " was a vector3 instead of a number

1 Like

Impressive, very nice. Let’s see Paul Allen’s swimming system

Can a default IdleAnimation and SwimAnimation be added?

1 Like

Long time since this reply, but how do you do chainable set methods?

I would assume it’s like this:

function class:SetSpeed()
    --dostuff
    return self
end

function class:SetPart()
    --dostuff
    return self
end

Since it returns self it could also ‘chain’ methods? Not sure how else you’d do it.

1 Like

Could someone re-write this so it works with normal terrain water? but just replaces the default swim system…

Im trying to use it with a custom made rig and i would rather use terrain water, but i dont really like the default swimming since it rotates the player weird.

how do i set this up, exactly?

is there any access to the game?

Make a local script in StarterPlayerScripts and put this code. Name the swim part in workspace Water. Add two animations in Replicated Storage name one SwimIdle and the other Swim (make your animations).

task.wait(.5)
local rs = game.ReplicatedStorage
local swimidle = rs:WaitForChild("SwimIdle")
local swim = rs:WaitForChild("Swim")

local Swimzone = require(game.ReplicatedStorage:WaitForChild("Swimming"))

local Zone = Swimzone.new(7, "Water", swimidle, swim, 50 )

Zone.startedSwimmingFunction = function()
	print("Started Swimming")
end
2 Likes

thank you so much! i really appreciate it.

1 Like