I’m currently designing a relatively simple run and crouching system, but I encountered a problem with the actions clashing with each other. If I run, crouch, and then let go of the run button while still holding the crouch button I go down to default walkspeed, then immediately down to crouching speed. The same applies in the reverse. I have made countless running and crouching systems in the past, but only with the UserInputService, and I would like to experiment with the ContextActionService.
Any ideas?
Here’s the code:
local cas = game:GetService("ContextActionService")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local walkSpeed = character:WaitForChild("Humanoid").WalkSpeed
local runSpeed, crouchSpeed = character.Humanoid.WalkSpeed + 5, character.Humanoid.WalkSpeed - 10
local running = false
local crouching, sliding = false, false
local function run(action, inputState)
if action == "run" and inputState == Enum.UserInputState.Begin then
if not running then
running = true
if crouching then
crouching = false
end
character.Humanoid.WalkSpeed = runSpeed
end
elseif inputState == Enum.UserInputState.End then
running = false
character.Humanoid.WalkSpeed = walkSpeed
end
end
local function crouch(action, inputState)
if action == "crouch" and inputState == Enum.UserInputState.Begin then
if not crouching and not running then
crouching = true
character.Humanoid.WalkSpeed = crouchSpeed
end
elseif inputState == Enum.UserInputState.End then
crouching = false
if not running then
character.Humanoid.WalkSpeed = walkSpeed
end
end
end
cas:BindAction("run", run, false, Enum.KeyCode.LeftShift)
cas:BindAction("crouch", crouch, false, Enum.KeyCode.LeftControl)
I think you can make a variable that store the current action. Then make the "inputState == Enum.UserInputState.End" only revert walkspeed if the "action" variable from the functions is equal to the current action. Make sure to set the current action variable to nil after resetting the humanoid walkspeed.
What you need is a type of xor gate system. This should work although you need to place the script inside StarterCharacterScripts for it to work properly:
local contextActionService = game:GetService"ContextActionService"
local humanoid = script.Parent:WaitForChild"Humanoid"
local defaultWalkSpeed = humanoid.WalkSpeed
local intValue = Instance.new"IntValue"
local run, crouch = 0, 0
contextActionService:BindAction("Run", function(_, inputState)
run = (inputState == Enum.UserInputState.Begin) and 1 or 0
intValue.Value = run + crouch
end, false, Enum.KeyCode.LeftShift)
contextActionService:BindAction("Crouch", function(_, inputState)
crouch = (inputState == Enum.UserInputState.Begin) and -1 or 0
intValue.Value = run + crouch
end, false, Enum.KeyCode.LeftControl)
intValue.Changed:Connect(function(value)
if value == 1 then -- Is running
humanoid.WalkSpeed = defaultWalkSpeed + 5
elseif value == -1 then -- Is crouching
humanoid.WalkSpeed = defaultWalkSpeed - 10
else -- Not running or crouching
humanoid.WalkSpeed = defaultWalkSpeed
end
end)
Edit: Actually there’s a problem but I’m working on a fix
Problem solved, this should work now:
local contextActionService = game:GetService"ContextActionService"
local humanoid = script.Parent:WaitForChild"Humanoid"
local defaultWalkSpeed = humanoid.WalkSpeed
local intValue = Instance.new"IntValue"
local run, crouch = 0, 0
contextActionService:BindAction("Run", function(_, inputState)
run = (inputState == Enum.UserInputState.Begin) and 2 or 0
intValue.Value = run + crouch
end, false, Enum.KeyCode.LeftShift)
contextActionService:BindAction("Crouch", function(_, inputState)
crouch = (inputState == Enum.UserInputState.Begin) and -1 or 0
intValue.Value = run + crouch
end, false, Enum.KeyCode.LeftControl)
intValue.Changed:Connect(function(value)
if value == 2 then -- Is running
humanoid.WalkSpeed = defaultWalkSpeed + 5
elseif value == -1 then -- Is crouching
humanoid.WalkSpeed = defaultWalkSpeed - 10
else -- Not running or crouching
humanoid.WalkSpeed = defaultWalkSpeed
end
end)