Player Unable to Jump

I am trying to make a script that changes a player’s JumpPower if they hold Space for more than a second, a “Charged Jump”.

However, the player is currently not able to jump, and I am stuck as to where to go with my script at this point.

Here is the Script:

Summary
local player = game.Players.LocalPlayer
local UIS = game:GetService("UserInputService")
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local basePower = 50
local jump_multi = 2 

local State = character:WaitForChild("State")

local inputTime



--InputBegan
UIS.InputBegan:Connect(function(input, gameProcessed)
	if input.UserInputType == Enum.UserInputType.Keyboard and input.KeyCode == Enum.KeyCode.Space then
		inputTime = time()
		humanoid.JumpPower = 0
		humanoid.Jump = false
	end
end)

--InputEnded
UIS.InputEnded:Connect(function(input, gameProcessed)
	if input.UserInputType == Enum.UserInputType.Keyboard and input.KeyCode == Enum.KeyCode.Space then
		
		if time() - inputTime >= 1 then
			print("Charge Jump Worked")
			humanoid.JumpPower = basePower * jump_multi
			if humanoid.JumpPower >= basePower then
				humanoid.Jump = true
			end
		elseif time() - inputTime <= 1 then
			print("Normal Jump Worked")
			humanoid.JumpPower = basePower
			if humanoid.JumpPower == basePower then
				humanoid.Jump = true
			end
		end
	end
end)

Edit: The two Prints after the Time checks are working, so the issue is just with the Jumps

1 Like

There’s a good chance that time returns a value in integer seconds rather than rational seconds, which makes your time counter inaccurate.

Can you try replacing all your time calls with os.clock or tick?

3 Likes

That could be, but the two Prints after the time checks are working, it is just the jump that is not happening.

1 Like

I tested this myself, and it looks like the humanoid will only jump in these circumstances if you use Humanoid:ChangeState instead of the Humanoid.Jump property.

Here is the edited local script I used, in StarterCharacterScripts:

local UIS = game:GetService("UserInputService")

local char = script.Parent
local humanoid = char.Humanoid

local basePower = 50
local multiplier = 2

humanoid.JumpPower = 0

local grounded = false
humanoid.StateChanged:Connect(function(_, new)
	grounded = new == Enum.HumanoidStateType.Running
		or new == Enum.HumanoidStateType.RunningNoPhysics
		or new == Enum.HumanoidStateType.Landed
end)

local lastCharge = math.huge
UIS.InputBegan:Connect(function(input, proc)
	if input.KeyCode == Enum.KeyCode.Space then
		lastCharge = os.clock()
		print("JumpPower set to 0")
		humanoid.JumpPower = 0
	end
end)

UIS.InputEnded:Connect(function(input, proc)
	if input.KeyCode == Enum.KeyCode.Space and grounded then
		local useCharge = os.clock() - lastCharge >= 1
		humanoid.JumpPower = basePower * (useCharge and multiplier or 1)
		print(useCharge and "JumpPower charge used" or "normal JumpPower")
		humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
	end
end)

I also added one other thing, which was a check to see if the character is on the ground. Otherwise, your script would theoretically make the humanoid jump whether they are on the ground or not.

A more complicated problem may be only letting the player charge a jump when they are on the ground. Currently, they can charge a jump in midair and bunny hop at boosted power.

1 Like

I have experimented with this, however I am using Gravity Controller, which requires Humanoid.PlatformStand = true at all times.

Setting Humanoid:ChangeState(Enum.HumanoidStateType.Jumping) does allow the player to Jump without any side effects while on the ground, but when the player is walking on the side a wall, they are still unable to Jump for some reason.

https://gyazo.com/f12a2797efef2b826dc5aad9c1321fc8

It is an issue with PlatformStanding being disabled, so I will have to find another work around, or another way to get the player to jump. It may be possible to Connect onJumpRequest somehow, or using a remote event. If you have any experience with the Gravity Controller or Connecting a Jump remotely then please feel free to continue assisting haha

1 Like

You might have to resort to making the character jump by giving it some Velocity or a BodyVelocity for a moment.
Since your character’s gravity isn’t guaranteed to point toward (0, -1, 0), giving the character vertical velocity will not cut it. You will need to get the direction of gravity and jump against that direction.

As an aside, I’d think making all jumps charged will feel awful, control-wise. If you want to make a normal, non-charged jump, then the jump will only trigger when the key is released, which is often 50 or so ms after pressing and will encourage destroying the keyboard by pecking it to get a faster release.
Instead, try making crouching (if you have such a mechanic) charge the jump, and jumping while crouching release the charged jump.

1 Like

If that’s the case, you would probably want to edit the ControlModule directly in StarterPlayer > StarterPlayerScripts > PlayerModule > ControlModule. Line 346 looks like the main culprit there.

You want to set it up so that it saves the last time you jumped in the main module. You can make a local lastCharge variable right before the ControlModule:OnRenderStepped function definition, and then make ControlModule:OnRenderStepped call a function on the active controller declaring whether the controller is trying to charge a jump, and storing the time if so.

This is the code I used there, (Lines 307-348):

-- NEW CODE [[
local lastCharge = math.huge
local chargeAcknowledged = false
--]]

function ControlModule:OnRenderStepped(dt)
	if self.activeController and self.activeController.enabled and self.humanoid then
		-- Give the controller a chance to adjust its state
		self.activeController:OnRenderStepped(dt)

		-- Now retrieve info from the controller
		local moveVector = self.activeController:GetMoveVector()
		local cameraRelative = self.activeController:IsMoveVectorCameraRelative()

		local clickToMoveController = self:GetClickToMoveController()
		if self.activeController ~= clickToMoveController then
			if moveVector.magnitude > 0 then
				-- Clean up any developer started MoveTo path
				clickToMoveController:CleanupPath()
			else
				-- Get move vector for developer started MoveTo
				clickToMoveController:OnRenderStepped(dt)
				moveVector = clickToMoveController:GetMoveVector()
				cameraRelative = clickToMoveController:IsMoveVectorCameraRelative()
			end
		end

		-- Are we driving a vehicle ?
		local vehicleConsumedInput = false
		if self.vehicleController then
			moveVector, vehicleConsumedInput = self.vehicleController:Update(moveVector, cameraRelative, self.activeControlModule==Gamepad)
		end

		-- If not, move the player
		-- Verification of vehicleConsumedInput is commented out to preserve legacy behavior,
		-- in case some game relies on Humanoid.MoveDirection still being set while in a VehicleSeat
		--if not vehicleConsumedInput then
			if cameraRelative then
				moveVector = calculateRawMoveVector(self.humanoid, moveVector)
			end
			self.moveFunction(Players.LocalPlayer, moveVector, false)
		--end
		
		--[[ old code

		-- And make them jump if needed
		self.humanoid.Jump = self.activeController:GetIsJumping() or (self.touchJumpController and self.touchJumpController:GetIsJumping())

		--]]
		
		-- NEW CODE [[

		-- create charge time if not acknowledged yet
		if not chargeAcknowledged and (self.activeController.isChargingJump 
			or self.touchJumpController and self.touchJumpController.isChargingJump) 
		then
			chargeAcknowledged = true
			lastCharge = os.clock()
		end

		-- Make them jump if the active controller says so
		local isJumping = self.activeController:GetIsJumping() or (self.touchJumpController and self.touchJumpController:GetIsJumping())
		if isJumping then
			chargeAcknowledged = false
			local useChargedJump = os.clock() - lastCharge > 1
			
			self.humanoid.JumpPower = useChargedJump and 100 or 50
		end
		self.humanoid.Jump = isJumping

		--]]
	end
end

You will probably have to minimally modify all of the child modules under ControlModule that deal with jumping, which would theoretically be Keyboard, TouchJump, and Gamepad:

Module Function Name Lines
Keyboard handleJumpAction 112-116
TouchJump self.jumpButton.InputBegan:connect(...), OnInputEnded 165-182
Gamepad handleJumpAction 94-97

For each of these, you will want to make it so self.isJumping = true when the input ends. For TouchJump, I would probably set self.isJumping = false after a delay, like a wait().

For Keyboard:

	--[[ old code

	local handleJumpAction = function(actionName, inputState, inputObject)
		self.jumpRequested = self.jumpEnabled and (inputState == Enum.UserInputState.Begin)
		self:UpdateJump()
		return Enum.ContextActionResult.Pass
	end

	--]]

	-- NEW CODE [[

	local handleJumpAction = function(actionName, inputState, inputObject)
		self.isChargingJump = self.jumpEnabled and (inputState == Enum.UserInputState.Begin)
		self.jumpRequested = self.jumpEnabled and (inputState == Enum.UserInputState.End)
		self:UpdateJump()
		wait()
		self.jumpRequested = false
		self:UpdateJump()
		return Enum.ContextActionResult.Pass
	end

	--]]

For Gamepad:

	--[[ old code
	local handleJumpAction = function(actionName, inputState, inputObject)
		self.isJumping = (inputState == Enum.UserInputState.Begin)
		return Enum.ContextActionResult.Sink
	end
	--]]

	-- NEW CODE [[

	local handleJumpAction = function(actionName, inputState, inputObject)
		self.isChargingJump = (inputState == Enum.UserInputState.Begin)
		self.isJumping = (inputState == Enum.UserInputState.End)
		wait()
		self.isJumping = false
		return Enum.ContextActionResult.Sink
	end

	--]]

For TouchJump:

	--[[ old code

	self.jumpButton.InputBegan:connect(function(inputObject)
		--A touch that starts elsewhere on the screen will be sent to a frame's InputBegan event
		--if it moves over the frame. So we check that this is actually a new touch (inputObject.UserInputState ~= Enum.UserInputState.Begin)
		if touchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch
			or inputObject.UserInputState ~= Enum.UserInputState.Begin then
			return
		end

		touchObject = inputObject
		self.jumpButton.ImageRectOffset = Vector2.new(146, 146)
		self.isJumping = true
	end)

	local OnInputEnded = function()
		touchObject = nil
		self.isJumping = false
		self.jumpButton.ImageRectOffset = Vector2.new(1, 146)
	end

	--]]

	-- NEW CODE [[

	self.jumpButton.InputBegan:connect(function(inputObject)
		--A touch that starts elsewhere on the screen will be sent to a frame's InputBegan event
		--if it moves over the frame. So we check that this is actually a new touch (inputObject.UserInputState ~= Enum.UserInputState.Begin)
		if touchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch
			or inputObject.UserInputState ~= Enum.UserInputState.Begin then
			return
		end

		touchObject = inputObject
		self.jumpButton.ImageRectOffset = Vector2.new(146, 146)
		--self.isJumping = true
		self.isChargingJump = true
	end)

	local OnInputEnded = function()
		touchObject = nil
		self.isChargingJump = false
		self.isJumping = true
		self.jumpButton.ImageRectOffset = Vector2.new(1, 146)
		wait()
		self.isJumping = false
	end

	--]]

Edit: I have only tested Keyboard, I will test Gamepad and TouchJump right now.

Edit 2: Gamepad works, but not TouchJump, fixing now…

Edit 3: The ControlModule's lastCharge variable should be initialized to math.huge, not -math.huge, my bad!

Edit 4: The ControlModule stores the TouchJump controller in a separate variable, self.touchJumpController, not self.activeController.

2 Likes

The fix should be working now! Let me know if you find any errors.

1 Like

Sorry for the late reply but I had a few finals to take care of.

But Wow! Everything is seemingly working fine right now, and honestly I would have never thought about changing the Control Module and its child scripts. You’re honestly a life saver! :joy:

I will be able to mess around with the controls of the game some more since I finished my finals, and I’ll definitely let you know if I come across any errors.

1 Like