Problem with movement system based on Quake

I am currently trying to make a custom movement system using a BodyVelocity. I used this article as a reference. I’m pretty sure I implemented everything correctly, but air strafing and some other movement tricks don’t work. In theory, I should be able to replicate the air strafing in the video in the article, but I can’t. I have also watched this Youtube video on the subject, and my code still seems correct, but I can’t perform any of the tricks in the video, like wall-running or zigzagging. I’ve also tried looking into the original code itself, but I couldn’t really understand anything.

Here is the place file:
movement test.rbxl (54.1 KB)

The movement script is in StarterCharacterScripts. I have also visualized the wishDir (blue) and the player’s velocity (green). Can somebody show me what I have done wrong in the script/what I have missed/what I need to implement?

Movement code if you're too lazy to download the file
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local character = script.Parent
local humanoid : Humanoid = character:WaitForChild("Humanoid")
local humanoidRootPart : BasePart = character:WaitForChild("HumanoidRootPart")

local camera = workspace.CurrentCamera
camera.FieldOfView = 90

local BodyVelocity ="BodyVelocity")
BodyVelocity.MaxForce =,0,1) * 2e4
BodyVelocity.Parent = humanoidRootPart

-- constants
local sv_ground_accelerate = 400
local sv_air_accelerate = 0
local sv_max_velocity_ground = 500
local sv_max_velocity_air = 1500
local sv_friction = 10

-- check if player is airborne
local function PlayerIsInAir()
	return humanoid.FloorMaterial == Enum.Material.Air


local function Accelerate(accelDir : Vector3, prevVelocity :Vector3, accelerate, maxVelocity, deltaTime)
	local projVel = prevVelocity:Dot(accelDir) -- vector projection of prev velocity onto accelDir
	local accelVel = accelerate * deltaTime -- accelerated velocity in direction of movement
	-- if necessary, truncate the accelerated velocity so the vector projection does not exceed max velocity
	if (projVel + accelVel) > maxVelocity then
		accelVel = maxVelocity - projVel
	return prevVelocity + accelDir * accelVel;

local function ApplyFriction(prevVelocity : Vector3, deltaTime)
	local speed = prevVelocity.Magnitude
	if speed ~= 0 then -- to avoid divide by 0 errors
		local drop = speed * sv_friction * deltaTime
		prevVelocity *= math.max(speed - drop, 0) / speed -- scale the velocity based on friction
	return prevVelocity

local function MoveGround(accelDir : Vector3, prevVelocity : Vector3, deltaTime)
	prevVelocity = ApplyFriction(prevVelocity, deltaTime)
	return Accelerate(accelDir, prevVelocity, sv_ground_accelerate, sv_max_velocity_ground, deltaTime);

local function MoveAir(accelDir : Vector3, prevVelocity : Vector3, deltaTime)
	return Accelerate(accelDir, prevVelocity, sv_air_accelerate, sv_max_velocity_air, deltaTime);

local function UpdateVelocity(deltaTime)
	local accelDir = humanoid.MoveDirection
	local prevVelocity = humanoidRootPart.AssemblyLinearVelocity
	local humanoidState = humanoid:GetState()
	if PlayerIsInAir() then
		BodyVelocity.Velocity = MoveAir(accelDir, prevVelocity, deltaTime)
		BodyVelocity.Velocity = MoveGround(accelDir, prevVelocity, deltaTime)


This is the code I used, I think the problem was that the velocity calculation was a bit off. Use it as a learning tool.
local player = game.Players.LocalPlayer
local char = player.Character
local torso = char:WaitForChild(“Torso”)

local function getMoveVector()
local moveVector =
local input_x = player:GetMouse().X
local input_y = player:GetMouse().Y
moveVector = moveVector +, 0, input_y)
return moveVector.unit * 5

local function getWishDir()
local wishDir =

local wishVel = getMoveVector()

local wishDirc =, 0, wishVel.z)
-- Remove y component
wishDirc = wishDirc.unit * 5

return wishDirc


local function getVelocity()
local wishDir = getWishDir()
local wishVel = wishDir

local currentVel = torso.Velocity
local vel =
vel = vel + wishVel
vel = vel - currentVel
vel = vel * 10

return vel


local function onInputBegan(input, processed)
if input.KeyCode == Enum.KeyCode.W then
torso.BodyVelocity.Velocity = torso.BodyVelocity.Velocity + getVelocity()


This code doesn’t really have the functionality I want. The problem with this code is that it just keeps on multiplying the velocity, so you get some really fast uncontrollable speeds.

What are you getting angry for? I just pointed out the flaw in your code.

The behavior of it is kinda weird. I had to make some adjustments because the code came with errors as well.

Well you see what the problem is and you are a competent coder so you will know what to do to fix it. Its clear that is multiplying at a crazy rate so stop it from doing that.

Why should I be the one to fix your code? Why did you give me broken code in the first place? I want to focus on what’s wrong with my code in this post.

You should not ask users to write complete pieces of code for you, did you not even read the rules you silly goose :crazy_face:

When did I ask somebody to write code for me? I’m asking for help here because I want someone to point out what’s wrong in my code, not rewrite it for me. If you can’t help me, you don’t have to keep replying.

You’re obviously new here. Maybe if you had been clear about what you wanted from the beginning, we could have helped you. As it stands now, it’s too late. We’ve already tried to help you and you’ve refused. If you can’t figure it out, that’s on you.