Detect key being held while holding another key / Holding two keys at the same time

Currently working on a Hajime no Ippo inspired boxing simulation project as my first serious project. My main focus, before actually getting to boxing itself, is implementing the default movement (outside of the boxing state), having in mind that players will eventually do roadwork.

I’ve designed a movement system with four states:
Walking (WASD) - Default, slowest method of moving;
Jogging (WASD + LShift) - Most likely going to be the most used method of movement, for being faster than walking with no stamina consumption;
Running (Double tap and hold W / W+W) - Consumes stamina at a moderate pace while moving fast. Pretty much the best option if you want to reach a location quickly, without emptying your stamina bar when you get there;
Dashing (Running + LShift) - Highest stamina consumption at the exchange of being the fastest speed a character can achieve.

While simply adding walking and running would be enough, I do plan on implementing two separate roadworks for players to train their character’s stamina or speed. Both running and dashing will be influenced by specific character stats.

Now that context is given, I’ve quickly ran with an issue on the implementation of movement. I’m using an InputHandler local script (placed within StarterCharacterScripts) that, as the name implies, handles the player’s input, with a module script (named DefaultMovement) as its child that handles the transition between movement states and the humanoid walkspeed value.
image

Tried setting both scripts up as simple as I could just to get things done for the moment, yet I can’t figure out how to approach jogging (and consequently, the other movement states after it).

I can’t figure out how to detect if a player is holding the LeftShift key WHILE walking. Output returns no errors, it just doesn’t work.
You’ll find both scripts below.

-- InputHandler
local Players = game:GetService("Players");
local UserInputService = game:GetService("UserInputService");

local player = Players.LocalPlayer;
local character = player.Character or player.CharacterAdded:Wait();
local humanoid = character:WaitForChild("Humanoid");

local DefaultMovement = require(script.DefaultMovement);
local isWalking = false
local isJogging = false

UserInputService.InputBegan:Connect(function(input, isProcessing)
	if isProcessing then return end

	if input.KeyCode == Enum.KeyCode.W or 
		input.KeyCode == Enum.KeyCode.A or
		input.KeyCode == Enum.KeyCode.S or
		input.KeyCode == Enum.KeyCode then
		DefaultMovement.StartWalking();
		isWalking = true
	end
end)	

UserInputService.InputBegan:Connect(function(input, isProcessing)
	if isProcessing then return end
	
	if isWalking and input.KeyCode == Enum.KeyCode.LeftShift then
		DefaultMovement.StartJogging();
		print("Debug: isJogging() was called") -- Is NOT sent in the output. This condition doesn't goes through at all.
		isJogging = true
	end
end)

print("Debug: UserInputService.InputBegan's connected function ended.") -- Went through and appears on the output.

UserInputService.InputEnded:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.W or 
		input.KeyCode == Enum.KeyCode.A or
		input.KeyCode == Enum.KeyCode.S or
		input.KeyCode == Enum.KeyCode then
		isWalking = false
	end
	
	if isWalking and input.KeyCode == Enum.KeyCode.LeftShift then
		DefaultMovement.StopJogging();
		isJogging = false
	end
end)
-- DefaultMovement (duh)
local DefaultMovement = {}

local Players = game:GetService("Players");
local player = Players.LocalPlayer;
local character = player.Character or player.CharacterAdded:Wait();
local humanoid = character:WaitForChild("Humanoid");

local walkingSpeed = 12;
local joggingSpeed = 20;
local runningSpeed = 32;
local dashingSpeed = 48;

local walkingState = false;
local joggingState = false;
local runningState = false;
local dashingState = false;

function DefaultMovement.StartWalking()
	walkingState = true;
	print(player.Name .. " is walking.");
	humanoid.WalkSpeed = walkingSpeed;
end

function DefaultMovement.StartJogging()
	joggingState = true;
	print(player.Name .. " is jogging.");
	humanoid.WalkSpeed = joggingSpeed;
end

function DefaultMovement.StopJogging()
	joggingState = false;
	print(player.Name .. " stopped jogging.");
	humanoid.WalkSpeed = walkingSpeed;
end

function DefaultMovement.StartRunning()
	runningState = true;
	print(player.Name .. " is running.");
	humanoid.WalkSpeed = runningSpeed;
end

function DefaultMovement.StopRunning()
	runningState = false;
	print(player.Name .. " stopped running.");
	humanoid.WalkSpeed = joggingSpeed;
end

function DefaultMovement.StartDashing()
	if runningState then
		dashingState = true;
		print(player.Name .. " is Dashing.");
		humanoid.WalkSpeed = dashingSpeed;
	end
end

function DefaultMovement.StopDashing()
	dashingState = false;
	print(player.Name .. " stopped dashing.");
	humanoid.WalkSpeed = runningSpeed;
end

return DefaultMovement

Any help is appreciated! I’m aware that I’m biting more than I can chew with such an ambitious project, but I’m trying my best to split everything into smaller parts to make it manageable, along with properly working on the game design before actually scripting the complex core mechanics.

Thank you in advance!

1 Like

Well, to detect a key like being HELD. you’d need to use some debouncing + while loop

UserInputService.InputBegan:Connect(function(input, isProcessing)
	if isProcessing then return end

	if input.KeyCode == Enum.KeyCode.W or 
		input.KeyCode == Enum.KeyCode.A or
		input.KeyCode == Enum.KeyCode.S or
		input.KeyCode == Enum.KeyCode then
		DefaultMovement.StartWalking();
		while isWalking == true do
print("Being held")
end
	end
end)	
UserInputService.InputEnded:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.W or 
		input.KeyCode == Enum.KeyCode.A or
		input.KeyCode == Enum.KeyCode.S or
		input.KeyCode == Enum.KeyCode then
		isWalking = false
	end
	
	if isWalking and input.KeyCode == Enum.KeyCode.LeftShift then
		DefaultMovement.StopJogging();
		isJogging = false
	end
end)

Which is basically just what you did, but without the loops.

1 Like

Your while loop will never run as isWalking isn’t set to true in your code.

1 Like

What about this which returns true when the key is being pressed?

game:GetService("UserInputService"):IsKeyDown(Enum.KeyCode.LeftShift)
1 Like

I just typed it out this isn’t an actual script… But you get the idea…

Still desperately need help with this. Can’t figure out what’s wrong with my logic here, even tried other approaches a LOT of times, and still couldn’t find a solution.

Currently, my InputHandler looks like this, and it does not work at all. The StartJogging() function never gets called.
I can’t figure out how to call a function under the condition of having two keys held down at the same time.

-- InputHandler
local Players = game:GetService("Players");
local UserInputService = game:GetService("UserInputService");

local player = Players.LocalPlayer;
local character = player.Character or player.CharacterAdded:Wait();
local humanoid = character:WaitForChild("Humanoid");

local DefaultMovement = require(script.DefaultMovement);
local isWalking = false
local isJogging = false

UserInputService.InputBegan:Connect(function(input, isProcessing)
	if isProcessing then return end

	if input.KeyCode == Enum.KeyCode.W or 
		input.KeyCode == Enum.KeyCode.A or
		input.KeyCode == Enum.KeyCode.S or
		input.KeyCode == Enum.KeyCode.D then
		DefaultMovement.StartWalking();
		isWalking = true
	end
end)    

UserInputService.InputBegan:Connect(function(input, isProcessing)
	if isProcessing then return end
	warn("The isWalking variable is " .. tostring(isWalking)) -- Get printed out and changes values
	if isWalking then
		if input.KeyCode == Enum.KeyCode.LeftShift then
			warn("Debug: UserInputService.InputBegan's connected function was called.") -- Never gets printed out
			DefaultMovement.StartJogging();
			isJogging = true
		end
	end
end)


warn("Debug: UserInputService.InputBegan's connected function ended.")

UserInputService.InputEnded:Connect(function(input)
	-- Also tried the standard "InputBegan" with "InputEnded" for holding down shift. Nothing.
end)
1 Like
if isProcessing then return end

I had no idea that gameProcessedEvent prevented multiple inputs happening at once. Simply removing that line of code solved my issue, along with replacing the two InputBegan with a single one, adding the jogging condition as an elseif (I admit that I had forgotten about elseifs).
If I’m being honest, the documentation does not explain it properly, and neither does most of the content creators — until now, I thought gameProcessedEvent prevented players triggering events by pressing an input while using any of Roblox built-in systems, such as typing in the chat.

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