How to limit AssemblyLinearVelocity when using a vector force?

Basically I’m scripting a velocity-based movement system and I’m currently trying to limit how fast the player can move.

Right now, I’m using a vector force to move the player. That works fine. I even have acceleration working so that it speeds up to a certain limit. I successfully made a system where the vector force does not increase past a certain point. HOWEVER, the problem is the AssemblyLinearVelocity of the HumanoidRootPart (which the vector force is applying itself to). It keeps increasing (which makes sense obviously) and especially when I jump, it gets out of control.

I want the AssemblyLinearVelocity to also be limited to a certain speed so that it cannot increase further.

I tried directly limiting it in my RunService function but this led to a lot of lag and weird physics with ApplyImpulse (which I use for jumping).

How can I limit the linear velocity? This is my code so far (yes I know it only moves them in one direction this is the very early stages, input direction will be added later):

local runService = game:GetService("RunService")
local uis = game:GetService("UserInputService")

local character = script.Parent
local humanoid: Humanoid = character.Humanoid
local hrp: BasePart = character.HumanoidRootPart

local MIN = math.min;
local MAX = math.max;

local BASE_MAX_SPEED = 20; -- viable number is 94 (using 20 for testing jump)
local REAL_MAX_SPEED = 100;
local ZERO_TO_MAX_TIME = 0.25;
local JUMP_ADDITION = 0.5;
local MULTIPLIER = 100;

local canJump = true;
local isRequestingJump = false;
local newMaxSpeed;
local accelRate;
local forwardVel;

local vectorForce = Instance.new("VectorForce")

local function setupVForce()
	vectorForce.Force = Vector3.zero
	vectorForce.Attachment0 = hrp.RootAttachment
	vectorForce.ApplyAtCenterOfMass = true
	vectorForce.Parent = hrp
end

local function calculateMaxSpeed()
	if not newMaxSpeed then newMaxSpeed = BASE_MAX_SPEED return end
	newMaxSpeed = MIN((newMaxSpeed + JUMP_ADDITION), REAL_MAX_SPEED)
end

local function calculateAccel()
	accelRate = (newMaxSpeed / ZERO_TO_MAX_TIME);
	forwardVel = 0;
end

local function calculateVel()
	forwardVel += accelRate;
	forwardVel = MIN(forwardVel, newMaxSpeed);
end

setupVForce();
calculateMaxSpeed();
calculateAccel();

uis.InputBegan:Connect(function(input, processed)
	if processed then return end
	
	if input.KeyCode == Enum.KeyCode.Space then
		isRequestingJump = true
		while (isRequestingJump) do
			task.wait()
			if not character or not humanoid or humanoid:GetState() == Enum.HumanoidStateType.Dead then return end

			if canJump then
				humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				hrp:ApplyImpulse(Vector3.new(0, 500, 0))
			end
		end
	end
end)

uis.InputEnded:Connect(function(input, processed)
	if processed then return end
	
	if input.KeyCode == Enum.KeyCode.Space then
		isRequestingJump = false
	end
end)

humanoid.StateChanged:Connect(function(oldState, newState)
	if newState == Enum.HumanoidStateType.Landed then
		canJump = true
	elseif newState == Enum.HumanoidStateType.Freefall then
		canJump = false
	end
end)

runService.RenderStepped:Connect(function(dt : number)
	
	calculateVel();
	
	local force = (forwardVel * MULTIPLIER);
	vectorForce.Force = Vector3.new(0, 0, -force);
	
end)
1 Like

Have you tried math.clamp to limit forces?

you can add a var to set the max allowed linear velocity and getting current assemblylinervelocity then you can separate the horizontal velocity x and z and if it exceeds it cales it down while preserving direction then you could sets the new asssembly keeping the original y velocity not sure if it will work without lagging since it was always laggy for me at least

local runService = game:GetService("RunService")
local uis = game:GetService("UserInputService")

local character = script.Parent
local humanoid: Humanoid = character.Humanoid
local hrp: BasePart = character.HumanoidRootPart

local MIN = math.min
local MAX = math.max

local BASE_MAX_SPEED = 20
local REAL_MAX_SPEED = 100
local ZERO_TO_MAX_TIME = 0.25
local JUMP_ADDITION = 0.5
local MULTIPLIER = 100
local MAX_LINEAR_VELOCITY = 50 -- maximum linear velocity you can modify it whatever you want

local canJump = true
local isRequestingJump = false
local newMaxSpeed
local accelRate
local forwardVel

local vectorForce = Instance.new("VectorForce")

local function setupVForce()
	vectorForce.Force = Vector3.zero
	vectorForce.Attachment0 = hrp.RootAttachment
	vectorForce.ApplyAtCenterOfMass = true
	vectorForce.Parent = hrp
end

local function calculateMaxSpeed()
	if not newMaxSpeed then newMaxSpeed = BASE_MAX_SPEED return end
	newMaxSpeed = MIN((newMaxSpeed + JUMP_ADDITION), REAL_MAX_SPEED)
end

local function calculateAccel()
	accelRate = (newMaxSpeed / ZERO_TO_MAX_TIME)
	forwardVel = 0
end

local function calculateVel()
	forwardVel += accelRate
	forwardVel = MIN(forwardVel, newMaxSpeed)
end

local function limitVelocity()
	local currentVelocity = hrp.AssemblyLinearVelocity
	local horizontalVelocity = Vector3.new(currentVelocity.X, 0, currentVelocity.Z)
	
	if horizontalVelocity.Magnitude > MAX_LINEAR_VELOCITY then
		local limitedVelocity = horizontalVelocity.Unit * MAX_LINEAR_VELOCITY
		hrp.AssemblyLinearVelocity = Vector3.new(limitedVelocity.X, currentVelocity.Y, limitedVelocity.Z)
	end
end

setupVForce()
calculateMaxSpeed()
calculateAccel()

uis.InputBegan:Connect(function(input, processed)
	if processed then return end
	
	if input.KeyCode == Enum.KeyCode.Space then
		isRequestingJump = true
		while (isRequestingJump) do
			task.wait()
			if not character or not humanoid or humanoid:GetState() == Enum.HumanoidStateType.Dead then return end

			if canJump then
				humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				hrp:ApplyImpulse(Vector3.new(0, 500, 0))
			end
		end
	end
end)

uis.InputEnded:Connect(function(input, processed)
	if processed then return end
	
	if input.KeyCode == Enum.KeyCode.Space then
		isRequestingJump = false
	end
end)

humanoid.StateChanged:Connect(function(oldState, newState)
	if newState == Enum.HumanoidStateType.Landed then
		canJump = true
	elseif newState == Enum.HumanoidStateType.Freefall then
		canJump = false
	end
end)

runService.RenderStepped:Connect(function(dt : number)
	calculateVel()
	
	local force = (forwardVel * MULTIPLIER)
	vectorForce.Force = Vector3.new(0, 0, -force)
	
	limitVelocity()
end)
2 Likes

this worked thanks!!
guess i’m onto input direction

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