Custom Character Controller Slippery?

I’m making a custom character controller and my character is weirdly slippery?

Here’s an example (I’m not turning slowly on purpose, I swear)

And here’s what my code looks like

function player:MoveAndSlide()
	
	rs.RenderStepped:Connect(function(dt)
		task.desynchronize()
		local factor = self.humanoid.MoveDirection * Vector3.new(self.acceleration, 0, self.acceleration) * Vector3.new(dt, 0, dt)

		if self.humanoid.MoveDirection.Magnitude ~= 0 then
			if self.state == 1 then
				self.state = 2
			end
			task.synchronize()

			self:Accelerate(factor)
		else
			if self.state == 2 then
				self.state = 1
			end
		task.synchronize()
			
			self:Deccelerate()
		end
	end)
	
end

function player:Accelerate(dir)
	
	self.hrp.AssemblyLinearVelocity += dir
	
end

function player:Deccelerate()
	self.hrp.AssemblyLinearVelocity = Vector3.new(self.hrp.AssemblyLinearVelocity.X * 0.95, self.hrp.AssemblyLinearVelocity.Y, self.hrp.AssemblyLinearVelocity.Z * 0.95)
end

I’m making a sonic game so the acceleration is a necessity, does anyone know how to fix this?
Thanks!

the function is literally named moveandslide

its just the name folk

its named that because the only experience that I have making controllers was in Godot

the function they use is :MoveAndSlide()

The slippery feeling is probably happening because you’re directly adding to AssemblyLinearVelocity every frame.

self.hrp.AssemblyLinearVelocity += dir

That keeps stacking velocity but when the player changes direction, the old horizontal velocity is still there. So the character keeps sliding in the previous direction instead of steering cleanly into the new one

for a sonic style controller, I’d separate the horizontal velocity, accelerate it toward the desired movement direction and clamp it to a max speed

Something like this

local function moveToward(current, target, maxDelta)
	local delta = target - current
	local distance = delta.Magnitude

	if distance <= maxDelta or distance == 0 then
		return target
	end

	return current + delta.Unit * maxDelta
end

function player:MoveAndSlide()
	rs.RenderStepped:Connect(function(dt)
		local velocity = self.hrp.AssemblyLinearVelocity
		local horizontal = Vector3.new(velocity.X, 0, velocity.Z)

		local moveDir = self.humanoid.MoveDirection
		local maxSpeed = self.maxSpeed or 80
		local acceleration = self.acceleration or 120
		local deceleration = self.deceleration or 80

		if moveDir.Magnitude > 0 then
			local targetVelocity = moveDir.Unit * maxSpeed
			horizontal = moveToward(horizontal, targetVelocity, acceleration * dt)
		else
			horizontal = moveToward(horizontal, Vector3.zero, deceleration * dt)
		end

		self.hrp.AssemblyLinearVelocity = Vector3.new(
			horizontal.X,
			velocity.Y,
			horizontal.Z
		)
	end)
end

This still gives you acceleration but instead of endlessly adding velocity, it steers the current velocity toward the input direction

Also I’d avoid using task.desynchronize() here unless you really need it. Character physics/control code is usually easier and safer to keep synchronized

2 Likes

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.