How To Keep Velocity When Jumping Mid-Air

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I want to make bhop system that wont reduce velocity at mid-air

  2. What is the issue? The main problem is that when the player jumps, about in the middle of the air jump he has a peak in speed and then this speed begins to decrease, it is not very good for bhop so I want to make so that the speed during the jump was always the same and at the end i want to do inertia (inertia has not yet started to do) here is a video of how it happens
    PS: speed in the lower left corner…

  3. What solutions have you tried so far? I’ve been trying to do a lot of different ways to keep my speed, but all of them ended up either an error or I went out into space.

some lua code that can provide you information about how my bhop did.

UserInputService.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.Space and humanoid.MoveDirection.Magnitude > 0 and humanoid.FloorMaterial ~= Enum.Material.Air then
		HRT:ApplyImpulse(humanoid.MoveDirection * 240)
		print(humanoid.MoveDirection * 240)
		if humanoid.FloorMaterial == Enum.Material.Air then
			-- unfinished code...
		end	
	end
end)

if you have any question, feel free to ask me

I’d use VectorForce, not ApplyImpulse.

Also, detecting when users jump by when they press space is not a good solution. Try using UserInputService.JumpRequest instead.

Off the top of my head, I would create a system that stores a player’s 2D velocity before they jump (2D because the Y velocity shouldn’t be affected by this), then while they’re in the air, make sure the magnitude of that 2D velocity doesn’t go below the stored velocity’s magnitude. This’d let the player turn without losing any velocity. If you want to make them faster with each jump you can also give them a small boost to the stored variable.

Ex:

-- pre jump
local boost = Vector2.new(15,15)
local storedVelocity = Vector2.new(charVelocity.X,charVelocity.Z)+boost

function onJump()
	-- loop run this function while in the air	

	local currentVelocity = Vector2.new(charVelocity.X,charVelocity.Z)
	
	if currentVelocity.Magnitude < storedVelocity.Magnitude then
		newVelocity = Vector2.new(charMoveDirection.X,charMoveDirection.Z).Unit*storedVelocity.Magnitude
		if newVelocity == newVelocity then -- make sure the values aren't NaN
			currentVelocity = newVelocity
		end
	end

end

Side note: I added the .Unit to the MoveDirection part because I’m not familiar enough to remember if MoveDirection’s magnitude is always <1 or if it can be greater than that. That’s why I added making sure the values aren’t NaN, so if the .Unit is unnecessary you can remove it and also remove that NaN check for optimization.

Also, this is just something I came up with quickly so it might not even work.

I have changed a bit but its seems like there is bug, i dont really know where but maybe Im doing something wrong? also I have changed vector2 to vector3 bc I cant apply vector2 velocity
btw here`s full code


function onJump()
	task.wait(0.1)
	print(humanoid.FloorMaterial)
	while humanoid.FloorMaterial == Enum.Material.Air do
		task.wait(0.01)
		local currentVelocity = Vector3.new(HRT.AssemblyLinearVelocity.X,0,HRT.AssemblyLinearVelocity.Z)
		print(currentVelocity)
		print(storedVelocity)
		if currentVelocity.Magnitude < storedVelocity.Magnitude then
			newVelocity = Vector3.new(humanoid.MoveDirection.X,0,humanoid.MoveDirection.Z).Unit*storedVelocity.Magnitude
			print(currentVelocity)
			print(newVelocity)
			if newVelocity == newVelocity then -- make sure the values aren't NaN
				currentVelocity = newVelocity
				HRT.AssemblyLinearVelocity = Vector3.new(currentVelocity)
			end
		end
	end
end


-- MainScript
UserInputService.InputBegan:Connect(function(input)
	if humanoid.MoveDirection.Magnitude > 0 and humanoid.FloorMaterial ~= Enum.Material.Air and input.KeyCode == Enum.KeyCode.Space then
		HRT:ApplyImpulse(humanoid.MoveDirection * 240)
		storedVelocity = Vector3.new(HRT.AssemblyLinearVelocity.X,0,HRT.AssemblyLinearVelocity.Z)
		--print(humanoid.MoveDirection * 240)
		onJump()
	end
end)

and also there is a bug that makes me fly, idk why


last numbers in output was
currentVelocity = 1.873291015625, 0, -35.07121658325195 - Client - BhopSystem:32
newVelocity = nan, nan, nan - Client - BhopSystem:33

when I using UserInputService.JumpRequest:Connect(function()
it does a lot of jumps soo i returned UserInputService.InputBegan because it calls only once

Right my bad, I forgot about that part, you should try this:

local HRP = script.Parent.HumanoidRootPart

local storedVelocity = Vector3.new()
local boost = Vector2.new(15,15)
function preJump()
	-- Run this once before jumping or right after jumping should also work.
	-- But make sure this runs one time before the onJump() function is called
	storedVelocity = Vector2.new(charVelocity.X,charVelocity.Z)+boost
end

function onJump()
	-- loop run this function while in the air	

	local currentVelocity = Vector2.new(charVelocity.X,charVelocity.Z)

	if currentVelocity.Magnitude < storedVelocity.Magnitude then
		local newVelocity = Vector2.new(charMoveDirection.X,charMoveDirection.Z)*storedVelocity.Magnitude
		currentVelocity = newVelocity
	end

	HRP.AssemblyLinearVelocity = Vector3.new(currentVelocity.X,HRP.AssemblyLinearVelocity.Y,currentVelocity.Z)

end

I think your bug came from overwriting the Y component of AssemblyLinearVelocity. This solution should fix that, but if it doesn’t then it’s probably because setting the AssemblyLinearVelocity.Y messes with acceleration due to gravity somehow. Test it and let me know if that’s the case.

Also I called the variable HRP because it’s the HumanoidRootPart, HRT works too, just doesn’t make sense as a variable name. That’s not what most people name it, it’s just a quirk of my coding style, I guess.

Update:
I made the solution far more complex than I should’ve, while testing the best I’ve gotten it working is actually very simple. I annotated the code for you if you wanted to read through, it’s not perfect so I figured you can still modify it how you want:

-- Services
local RunService = game:GetService("RunService")
local UIS = game:GetService("UserInputService")

-- Variables
local hum = script.Parent:WaitForChild("Humanoid")
local HRP = script.Parent:WaitForChild("HumanoidRootPart")

local boost = 5 -- The boost in velocity you get each time you jump
-- Lowering this will make it take more jumps to reach max speed, but also lower the max speed.
-- If you wanted to make it take more jumps to reach max speed and keep the max speed higher, you could lower this then raise the number you divide dT by to bring the max speed back up. The only issue is this would make it easier to maintain speed, but that's not necessarily a bad thing if you're going to have a wider range for your speed.
local maxBoost = boost*15 -- Max amount the boost can contribute
local totalBoost = 0

-- Detect jump, since you said you wanted to use inputs, I kept it at that
UIS.InputBegan:Connect(function(input,gpe)
	if not gpe then
		if input.KeyCode == Enum.KeyCode.Space and hum.MoveDirection.Magnitude > 0 and hum.FloorMaterial ~= Enum.Material.Air then
			totalBoost += boost -- Contribute to the total boost when you jump
		end
	end
end)

-- loop
RunService.RenderStepped:Connect(function(dT)
	if hum.MoveDirection.Magnitude <= .5 or hum.FloorMaterial ~= Enum.Material.Air then
		totalBoost = math.clamp(totalBoost+(0-totalBoost)*(dT/1),0,maxBoost) -- Diminish value when on ground, 
		-- This makes it so it's crucial time your jumps nearly perfectly to minimize the diminishing
		-- The more you divide dT by the less it will diminish when you land, this both makes it easier to time and gives you a higher top speed before it balances out naturally because of how linear interpolation works.
	end

	HRP.AssemblyLinearVelocity = Vector3.new(0,HRP.AssemblyLinearVelocity.Y)+hum.MoveDirection*hum.WalkSpeed+hum.MoveDirection*totalBoost -- Make the player
end)
2 Likes

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