There are plenty of tutorials on how to create a double jump system, but I want to implement a variable-height jump (or “half-jump” system) in my game. The jump height should depend on how long the player holds the jump key.
For example, let’s say the maximum hold time is 1 second. If the player holds the jump key for 0.7 seconds, they should jump 70% of the maximum jump height.
Additionally, I don’t want the system to wait for the player to release the key before determining the jump height. The character should start jumping immediately when the key is pressed, while the system monitors how long the key is held. As soon as the player releases the key, the character should stop ascending.
Many 2D platformer games on Steam use this mechanic, but the only Roblox game I know that features it is Chickynoid 2.0. I’ll leave the link below, feel free to check it out if you want a better understanding of the system I’m aiming for.
The way that many other games achieve this is by dramatically increasing the gravity force on the player when the jump button is released. I’m not sure how Chickynoid handles it exactly, but given how the default Roblox Humanoid-based Characters handle jumping with JumpHeight, I’m not sure of the best approach here.
You might try setting the JumpHeight to 0 for a moment after the Jump button is released.
If that doesn’t work, try moving the Character to their current position (i.e. teleport them to where they already are) as that should cancel their vertical movement and start them falling immediately, even if they still had some height left to jump.
I created this script using ChatGPT, and surprisingly, it works perfectly. Not gonna lie, if AI keeps performing like this, it might just take over my job lol.
For future viewers, here’s the script:
Note: The maxJumpVelocity variable does not determine your jump height. If you want to adjust your jump height, modify humanoid.JumpHeight or humanoid.JumpPower instead.
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local jumpKey = Enum.KeyCode.Space -- Jump key
local maxJumpTime = 1 -- Max time to hold jump
local minJumpVelocity = 20 -- Minimum jump strength
local maxJumpVelocity = 60 -- Maximum jump strength
local isJumping = false
local jumpStartTime = 0
-- Function to start jump
local function startJump()
if humanoid:GetState() == Enum.HumanoidStateType.Freefall then return end -- Prevent mid-air jumps
isJumping = true
jumpStartTime = tick()
end
-- Function to stop jump smoothly
local function stopJump()
if isJumping then
local holdTime = math.min(tick() - jumpStartTime, maxJumpTime)
local jumpVelocity = minJumpVelocity + ((maxJumpVelocity - minJumpVelocity) * (holdTime / maxJumpTime))
-- Only reduce velocity if the player is still moving up
if rootPart.AssemblyLinearVelocity.Y > 0 then
rootPart.AssemblyLinearVelocity = Vector3.new(
rootPart.AssemblyLinearVelocity.X,
math.min(rootPart.AssemblyLinearVelocity.Y, jumpVelocity), -- Prevent extra force
rootPart.AssemblyLinearVelocity.Z
)
end
end
isJumping = false
end
-- Detect jump key press
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if not gameProcessed and input.KeyCode == jumpKey then
startJump()
end
end)
-- Detect jump key release
UserInputService.InputEnded:Connect(function(input, gameProcessed)
if input.KeyCode == jumpKey then
stopJump()
end
end)