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 = Instance.new("BodyVelocity")
BodyVelocity.MaxForce = Vector3.new(1,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
end
-- http://adrianb.io/2015/02/14/bunnyhop.html
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
end
return prevVelocity + accelDir * accelVel;
end
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
end
return prevVelocity
end
local function MoveGround(accelDir : Vector3, prevVelocity : Vector3, deltaTime)
prevVelocity = ApplyFriction(prevVelocity, deltaTime)
return Accelerate(accelDir, prevVelocity, sv_ground_accelerate, sv_max_velocity_ground, deltaTime);
end
local function MoveAir(accelDir : Vector3, prevVelocity : Vector3, deltaTime)
return Accelerate(accelDir, prevVelocity, sv_air_accelerate, sv_max_velocity_air, deltaTime);
end
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)
else
BodyVelocity.Velocity = MoveGround(accelDir, prevVelocity, deltaTime)
end
end
RunService.RenderStepped:Connect(UpdateVelocity)