How to limit the players speed without using walkspeed?

To my understanding there is no other way to slow down the player without changing their walkspeed.

This is interesting and may be useful…

I am not looking to overhaul the whole movement system I am just looking to limit the players speed like changing walkspeed from 16 to 8 just using something else other than WalkSpeed for example Velocity but that seems to be a dead end so far

What’s the point not to use walkspeed? It just seems like a route to a long time of code; is there a reason for this? Because if you want to slow down the player, I would use @RecanValor’s method. Can you enlighten me on why you don’t want to use walkspeed @xDeltaXen?

1 Like

WalkSpeed is not an instant change in walkspeed I ned it to go from like Velocity.Magnitude = 16 to Velocity.Magnitude = 8 instantly but if I change walkspeed then It will not be an instant change it will be a quick change but it wont instantly go from a Magnitude of 16 to a magnitude of 8.

then just set the velocity.magnitude of the character to 0 and set the walkspeed to 0 and then after you do that instantly set the walkspeed to the desired speed

Doing Velocity = Vector3.new(0, 0, 0) will stop the player completely

right so you do it and follow it up with the speed you want on the next line

I want it to slow down the player not stop and start them every time

what?? its sounds like you want it to instantly go from a set speed to a lower one instantly, but the problen is that changing walkspeed isnt instant.

what i was saying is that you just set velocity to 0 and then instantly set it to the speed you want after that.

if that still doesnt work or if i dont understand you maybe you use a number tween or something

1 Like

I don’t want to do it by changing the walkspeed. I want to do it by not changing the walkspeed but I also don’t want the player to stop and then start because that would be very noticable.

Alright. I highly do not recommend it but there is a way to limit the velocity of a player is by using something called a VectorForce and some math. The reason being is because humanoid exerts a force on the HRP so you just have to negate that force.

You may have heard of a PID controller before. Basically it is a way to use math functions to achieve a goal e.g. rotation speed of a wheel. You can use it to make sure the character does not travel faster than a specified velocity

I do NOT recommend that as there are much better ways.

The second way you can do it is by limiting the MoveDirection to something less.
The third way you can do it by using a BodyVelocity to move the character instead.

Both the second and third option require you to create an entirely different system.

What exactly do you want to use it for and why do you not want to use WalkSpeed?

I disagree and this thread is getting silly.

I printed out the WalkSpeed and the velocity every physics frame while moving and changing WalkSpeed.

The first number (16, 8, 32) is the WalkSpeed. The second number (e.g. 13.86172…) is the HumanoidRootPart’s Velocity.Magnitude.

image

In other words, it maybe takes two frames to change velocity?

Here's the code if you want to recreate this
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local root = character:WaitForChild("HumanoidRootPart")
local default = humanoid.WalkSpeed

local speeds = {
	default / 2,
	default,
	default * 2
}

for i = 1, #speeds do
	local b = Instance.new("TextButton")
	b.Text = "Set speed to " .. speeds[i]
	b.Size = UDim2.fromOffset(200, 30)
	b.Position = UDim2.fromOffset(100, 100 + (i - 1) * 40)
	b.MouseButton1Click:Connect(function()
		
		humanoid.WalkSpeed = speeds[i]
		
		warn("==== CHANGED SPEED TO " .. speeds[i] .. " ====")
	end)
	b.Parent = script.Parent
end

game:GetService("RunService").Heartbeat:Connect(function()
	print(humanoid.WalkSpeed, root.Velocity.Magnitude)
end)

game:GetService("UserInputService").InputBegan:Connect(function(input, gp)
	if not gp and input.KeyCode == Enum.KeyCode.W then
		warn("==== HOLDING W ====")
	end
end)

game:GetService("UserInputService").InputEnded:Connect(function(input, gp)
	if not gp and input.KeyCode == Enum.KeyCode.W then
		warn("==== RELEASED W ====")
	end
end)

If you really, absolutely, positively, need your speed to change on that exact frame, you can do this:

if humanoid.FloorMaterial then
  local speed = root.Velocity.Magnitude
  if speed > 0 then
    local currentSpeedPercent = speed / humanoid.WalkSpeed
    root.Velocity = root.Velocity.Unit * currentSpeedPercent * NEW_SPEED
  end
end

humanoid.WalkSpeed = NEW_SPEED
Which I tested as well...
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local root = character:WaitForChild("HumanoidRootPart")
local default = humanoid.WalkSpeed

local speeds = {
	default / 2,
	default,
	default * 2
}

for i = 1, #speeds do
	local b = Instance.new("TextButton")
	b.Text = "Set speed to " .. speeds[i]
	b.Size = UDim2.fromOffset(200, 30)
	b.Position = UDim2.fromOffset(100, 100 + (i - 1) * 40)
	b.MouseButton1Click:Connect(function()
		
		if humanoid.FloorMaterial then
			local speed = root.Velocity.Magnitude
			if speed > 0 then
				local currentSpeedPercent = speed / humanoid.WalkSpeed
				root.Velocity = root.Velocity.Unit * currentSpeedPercent * speeds[i]  
			end
		end
		
		humanoid.WalkSpeed = speeds[i]
		
		warn("==== CHANGED SPEED TO " .. speeds[i] .. " ====")
	end)
	b.Parent = script.Parent
end

game:GetService("RunService").Heartbeat:Connect(function()
	print(humanoid.WalkSpeed, root.Velocity.Magnitude)
end)

game:GetService("UserInputService").InputBegan:Connect(function(input, gp)
	if not gp and input.KeyCode == Enum.KeyCode.W then
		warn("==== HOLDING W ====")
	end
end)

game:GetService("UserInputService").InputEnded:Connect(function(input, gp)
	if not gp and input.KeyCode == Enum.KeyCode.W then
		warn("==== RELEASED W ====")
	end
end)

…And the results:

image

There. Velocity changes matching WalkSpeed changes on the exact frame that you set them. If that doesn’t answer your question:

Then I don’t know what will.

Edit: By the way, you can’t really use BodyVelocity for this. Humanoid walking is not based on physics, exactly.

if I set NEW_SPEED to 0 then the player still moves that is the problem that I had earlier, but printing out root.Velocity gives 0, 0, 0 even though NEW_SPEED = 0 but the player is still moving. I don’t know why this is happening.

Apply Impulse is reliable but is not as smoothe as I would like and you cannot control it like you you can with WalkSpeed.

I don’t think it’s silly it’s just I don’t think I clarified what I want properly.

I want to be able to control the speed that the player moves without using walkspeed, I want to be able to set the max speed I want (studs per second) and I want it to be somewhat exact. its like walkspeed but only not walkspeed, using some other thing like a bodymover or velocity.

I ran a test and with NEW_SPEED = 0 the player is still going around 12stud/second?

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local root = character:WaitForChild("HumanoidRootPart")
local default = humanoid.WalkSpeed


local OldPos = root.Position
local Old = tick()
local NEW_SPEED = 0

while wait() do

	if humanoid.FloorMaterial then
		local speed = root.Velocity.Magnitude
			local currentSpeedPercent = speed / humanoid.WalkSpeed
			root.Velocity = root.Velocity.Unit * currentSpeedPercent * NEW_SPEED
	end
	if tick() - Old >= 1 then
		print((root.Position - OldPos).Magnitude)
		OldPos = root.Position
		Old = tick()
	end
end

image

That shows that I was actually going 12 - 12.5 studs per second while my velocity showed zero (root.Velocity). So I cannot control the studs per second I would like to go.

You forgot the

humanoid.WalkSpeed = NEW_SPEED

line in your test. That’s an important part :slight_smile:

I re-clarified what I want and that I don’t want to use WalkSpeed, "
How to limit the players speed without using walkspeed?"

I mean… You could do this, but it seems dumb. But since you insist:

Every frame, check how far the player went on the XZ axis. If they went further than the allowed number of studs, move them back along that vector to correct for the XZ movement.

Only do this in certain states (e.g. don’t affect ragdoll).

Proof of concept:

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")

local maxSpeed = 8

local last = root.Position

-- set of states to limit speed during
local limitedSpeedState = {
	[Enum.HumanoidStateType.Climbing] = true,
	[Enum.HumanoidStateType.RunningNoPhysics] = true,
	[Enum.HumanoidStateType.Running] = true,
	[Enum.HumanoidStateType.Jumping] = true,
	[Enum.HumanoidStateType.Landed] = true,
	[Enum.HumanoidStateType.Freefall] = true,
	--[Enum.HumanoidStateType.Swimming] = true,
}

game:GetService("RunService").Stepped:Connect(function(t, dt)
	local now = root.Position
	local state = humanoid:GetState()
	if limitedSpeedState[state] then
		local vec = (now - last) * Vector3.new(1, 0, 1)
		local vel = vec.Magnitude / dt
		
		if vel > maxSpeed then
			local new = last + vec.Unit * maxSpeed * dt
			local pos = Vector3.new(new.X, root.Position.Y, new.Z)
			root.CFrame = root.CFrame + (pos - root.Position) 
			print(string.format("was %.1f\tnow %.1f", vel, (root.Position - last).Magnitude / dt))
		end
	end
	last = root.Position
end)
1 Like

I can’t use teleporting. I am doing on the client and I have download an anti cheat module that is on the server and the anti tp will pick this up.Why is this not possible with just using Velocity and applyimpulse or something?

It works well but is there any possibility instead of doing tp it uses velocity instead because this is exactly what I want just not using tp as tp can be unreliable when falling and etc.

Because Humanoids don’t really use physics for most of the time. And when they do, it’s weird half-physics that’s deep in the engine.

Not that I’m aware of. I gave it a shot, but its buggy, because Humanoids really hate physics:

My somewhat failed attempt
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")

local maxSpeed = 1

-- set of states to limit speed during
local limitedSpeedState = {
	[Enum.HumanoidStateType.Climbing] = true,
	[Enum.HumanoidStateType.RunningNoPhysics] = true,
	[Enum.HumanoidStateType.Running] = true,
	[Enum.HumanoidStateType.Jumping] = true,
	[Enum.HumanoidStateType.Landed] = true,
	[Enum.HumanoidStateType.Freefall] = true,
	--[Enum.HumanoidStateType.Swimming] = true,
}

local last = root.Position
game:GetService("RunService").Stepped:Connect(function(t, dt)
	local now = root.Position
	
	if limitedSpeedState[humanoid:GetState()] then
		local vec = root.AssemblyLinearVelocity * Vector3.new(1, 0, 1)
		local vel = vec.Magnitude
		
		if vel > maxSpeed then
			local new = vec.Unit * maxSpeed
			local newVel = Vector3.new(new.X, root.AssemblyLinearVelocity.Y, new.Z)
			root.AssemblyLinearVelocity = newVel 
		end
	end
	
	last = now
end)

-- try to force it to keep in a physics mode? (this doesn't work really)
while true do
	local old, new = humanoid.StateChanged:Wait()
	if new == Enum.HumanoidStateType.RunningNoPhysics then
		 humanoid:ChangeState(Enum.HumanoidStateType.Running)
	end
end

That’s the limit of my knowledge. Good luck!

1 Like