Trying to make air strafing

Hello, I’m trying to remake air strafing for a game, I’m mainly using this code, as i’ve seen in other posts, but when I tried to remake it, it just sent me flying extremely fast out of the baseplate. Localscript:

local serverVars = {
	airacceleration = 10;
	maxacceleration = 60;
	friction = 1
}

local accelDir = Vector3.new(0,0,0)
local playerVelocity = Vector3.new(0,0,0)
local prevVelocity = Vector3.new(0,0,0)

local function onGround()
	local checkRay = Ray.new(Char:GetPrimaryPartCFrame().p, Vector3.new(0,-6,0))
	local hit,pos,normal = workspace:FindPartOnRay(checkRay, Char)
	if hit ~= nil then
		return true
	end
	return false
end

local function accelerate(Direction, prevVelocity, DeltaTime)
	local projection = prevVelocity:Dot(Direction) -- problem is probably here
	local acceleration = serverVars.airacceleration * DeltaTime
	print(acceleration, projection)
	if (projection + acceleration > serverVars.maxacceleration) then
		acceleration = serverVars.maxacceleration-projection
	elseif (projection + acceleration < -serverVars.maxacceleration) then
		acceleration = serverVars.maxacceleration+projection
	end
	return prevVelocity + Direction * acceleration
end

local function groundMove(Direction, prevVelocity, DeltaTime)
	local speed = prevVelocity.magnitude
	if speed ~= 0 and onGround() then
		local drop = speed * 1 * DeltaTime
		prevVelocity = prevVelocity * math.max(speed - drop, 0) / speed
	end
	return accelerate(Direction, prevVelocity, DeltaTime)
end


local Time = tick()
function updateAirStrafe(DeltaTime)
	if w then -- defined later on code with UserInputService
		accelDir = accelDir + Vector3.new(1,0,0)
	end
	if s then -- defined later on code with UserInputService
		accelDir = accelDir + Vector3.new(-1,0,0)
	end
	if a then -- defined later on code with UserInputService
		accelDir = accelDir + Vector3.new(0,0,1)
	end
	if d then -- defined later on code with UserInputService
		accelDir = accelDir + Vector3.new(0,0,-1)
	end
	if not onGround() then
		playerVelocity = accelerate(accelDir, playerVelocity, DeltaTime)
		prevVelocity = playerVelocity
		local posDelta = bodyvelocity.Velocity + playerVelocity
		print(posDelta)
		Char.HumanoidRootPart.Velocity = posDelta+Vector3.new(0,3,0)
	end
end
spawn(function()
	game:GetService("RunService").RenderStepped:Connect(function()
	    local t = tick()
	    local dt = t - Time
	    Time = t
	
	    updateAirStrafe(dt)
	end)
end)

tl;dr Help me fix bhop script up here

4 Likes

I think all you have to do is redefine accelDir every time you use the updateAirStrafe function:

function updateAirStrafe(DeltaTime)

	--add this part here
	accelDir = Vector3.new()

	--continue on with the rest of the function

Since you are using it in a RunService loop, accelDir will just keep adding to itself without ever reseting. Dot products also factor in magnitude, so prevVelocity:Dot(Direction) will increase/decrease per frame from Direction's magnitude. It might be helpful to use prevVelocity:Dot(Direction.Unit) as well, it depends.

2 Likes

New issue, I’m just floating up forever…

local serverVars = {
	airacceleration = 10;
	maxacceleration = 60;
	friction = 1
}

local accelDir = Vector3.new(0,0,0)
local playerVelocity = Vector3.new(0,0,0)
local prevVelocity = Vector3.new(0,0,0)

local function onGround()
	local checkRay = Ray.new(Char:GetPrimaryPartCFrame().p, Vector3.new(0,-6,0))
	local hit,pos,normal = workspace:FindPartOnRay(checkRay, Char)
	if hit ~= nil then
		return true
	end
	return false
end

local function accelerate(Direction, prevVelocity, DeltaTime)
	local projection = prevVelocity:Dot(Direction.Unit)
	local acceleration = serverVars.airacceleration * DeltaTime
	print(acceleration, projection)
	if (projection + acceleration > serverVars.maxacceleration) then
		acceleration = serverVars.maxacceleration-projection
	elseif (projection + acceleration < -serverVars.maxacceleration) then
		acceleration = serverVars.maxacceleration+projection
	end
	return prevVelocity + Direction * acceleration
end

local function groundMove(Direction, prevVelocity, DeltaTime)
	local speed = prevVelocity.magnitude
	if speed ~= 0 and onGround() then
		local drop = speed * 1 * DeltaTime
		prevVelocity = prevVelocity * math.max(speed - drop, 0) / speed
	end
	return accelerate(Direction, prevVelocity, DeltaTime)
end


local Time = tick()
function updateAirStrafe(DeltaTime)
	if w then
		accelDir = accelDir + Vector3.new(1,0,0)
	end
	if s then
		accelDir = accelDir + Vector3.new(-1,0,0)
	end
	if a then
		accelDir = accelDir + Vector3.new(0,0,1)
	end
	if d then
		accelDir = accelDir + Vector3.new(0,0,-1)
	end
	if not onGround() then
		playerVelocity = accelerate(accelDir, playerVelocity, DeltaTime)
		playerVelocity = playerVelocity + (Vector3.new(0,workspace.Gravity,0) * DeltaTime)
		prevVelocity = playerVelocity
		local posDelta = bodyvelocity.Velocity + playerVelocity
		print(posDelta)
		Char.HumanoidRootPart.Velocity = posDelta+Vector3.new(0,3,0)
	end
end
spawn(function()
	game:GetService("RunService").RenderStepped:Connect(function()
	    local t = tick()
	    local dt = t - Time
	    Time = t
		accelDir = Vector3.new()
	
		playerVelocity = Vector3.new(0,0,0)
		prevVelocity = Vector3.new(0,0,0)
	
	    updateAirStrafe(dt)
	end)
end)
1 Like

So just as a very quick optimization, though this won’t solve your problem, RunService.RenderStepped returns the amount of time since the last step, so you could very easily remove t and Time and place dt in the function argument:

spawn(function()
	game:GetService("RunService").RenderStepped:Connect(function(dt)
		accelDir = Vector3.new()

		--etc

Also, I don’t think you need to reset playerVelocity and prevVelocity every step, or at least I don’t think it’s the solution.

The problem may also be coming from setting Char.HumanoidRootPart.Velocity with an offset of (0,3,0) every frame in the updateAirStrafe function, try removing it and see what happens.

5 Likes

Thanks, now I only gotta fix the problem of velocity not resetting when I jump second time, other than that all is fine!

1 Like