How to limit the players speed without using walkspeed?

I have tried using body velocity but it does not seem to be working

I’m wrong, sorry about that! I had forgotten how BodyVelocities work. Here is some code:

local MAX_SPEED = 20

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local LocalPlayer = Players.LocalPlayer

wait(5)

local humanoidRootPart = LocalPlayer.Character.PrimaryPart
while true do
	local velocity = humanoidRootPart.AssemblyLinearVelocity
	if velocity.Magnitude > MAX_SPEED then
		local mass = humanoidRootPart.AssemblyMass
		local impulse = (velocity.Unit*MAX_SPEED - velocity)*Vector3.new(mass, mass, mass)
		humanoidRootPart:ApplyImpulse(impulse)
	end
	RunService.Stepped:Wait()
end

It might not work well with characters though, the character controller tends to override physics changes.

This script works but if I set max speed to zero then it still will stop the player completely how can I fix this.

Do you know any other ways of doing this because it is really important that I find alternative that I can control like 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: