Help With C to Crawl and C to Crawl Button

Hello. I am stuck with a script that doesn’t work:

local userinputservice = game:GetService("UserInputService")
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local isrunning = false
local anim = humanoid.Animator:LoadAnimation(script:WaitForChild("Crawl"))

userinputservice.InputBegan:Connect(function(key)
	if key.KeyCode == Enum.KeyCode.C or key.KeyCode == Enum.KeyCode.LeftControl then
		if not isrunning then
			isrunning = true
			humanoid.WalkSpeed = 8
			anim:Play()
		if isrunning then
			anim:Stop()
			humanoid.WalkSpeed = 16
				isrunning = false
			end
		end
	end
end)

It’s just not letting me crawl and I have been staring at this script for about 2 hours please help

1 Like
  • maybe you can yield the script with WaitForChild() until it finds the animator
  • possibly your animation’s priority isn’t set to action
2 Likes

Like this?


(Edit: This didn’t work. Thanks for the help though)

You are setting the isrunning variable to true so it is stopping again right after.
Try using elseif.

if not isrunning then
	isrunning = true
	humanoid.WalkSpeed = 8
	anim:Play()
  elseif isrunning then
	anim:Stop()
	humanoid.WalkSpeed = 16
	isrunning = false
end
1 Like

I know this isn’t your question, but I have some solid advice related in the fact you want to crawl with multiple input options (keys, gui buttons, gamepads, etc), and I see the same bad habit all the time. Using your current method of just checking the inputs and doing everything raw right there in the input func seems intuitive at first, until you consider how it will interact with other mechanics in your game.

What do I mean?
How are you going to stop players from jumping while crawling?
How are you going to stop players from sprinting while crawling?
How are you going to stop players from crawling and standing really fast to make their hitbox harder to hit?
How are you going to stop players from standing up in areas that they are not tall enough for and possibly clipping out of bounds?
Where are you going to put the code to check for all this stuff?

My Point:
All of these questions have an obvious answer when you change how the control script functions, and operates with the rest of your code.

My Advice:
From my experience, breaking the code down into seperate functions can make your character actions much more accessible to you as the developer.

Very Basic ControlScript Example:

local UIS = game:GetService("UserInputService")
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")

--controls info
local Controls = {
	["Crouch"] = {"C","LeftControl","ButtonR3"},
	["Sprint"] = {"LeftShift","ButtonL3"},
	["Jump"] = {"Space","ButtonA"}
}

--start of state info
local State = "Spawning" --store our current state
local StateTick = 0 --store the tick we last changed states
local TransitionTime = 0 --current cooldown before transitioning to the next state

--run this after a state change to transition the humanoid into it's new state
function UpdateHumanoid()
	--special exceptions (e.x there isn't enough room to stand up here! stay in crouch/prone!/prone blocked!)
	--play transition tweens (WalkSpeed,HipHeight,Etc)
	--update TransitionTime to prevent player changing states too fast
end

local Actions = {}
--set state to Walking
function Actions.Walk()
	State = "Walking"
end

--set state to Sprinting
function Actions.Sprint()
	State = "Sprinting"
end

--handle jump state logic
function Actions.Jump()
	if State == "Walking" then
		State = "Jumping"
	end
	if State == "Jumping" then
		if Humanoid.FloorMaterial then
			ProcessInputState()--Go Back And Figure out what the heck we should be doing right now!
		end
	end
	if State == "Crouching" then --crouch -> walk
		State = "Walking"
	end
	if State == "Prone" then --prone -> crouch
		State = "Crouching"
	end
	return true--update state tick
end

function Actions.Crouch()
	if State == "Sliding" then --sliding -> sliding
		--if it's been long enough return to the crouching state?
		return false--do not update state tick or we will slide forever lol
	end

	if State == "Sprinting" then --sprinting -> sliding
		State = "Sliding"
	else
		if State == "Crouching" then --crouching -> prone
			State = "Prone"
		else
			State = "Crouching" --otherwise just crouch
		end
	end
	return true--update state tick
end

function ProcessInputState()--check what buttons we're holding
	local Now = tick()--when is right now?
	if Now < StateTick+TransitionTime then
		return--unable to change action at this time, another action is till being performed
	end
	for ActionName,InputList in pairs (Controls) do
		for Index,KeyCodeName in pairs (InputList) do
			if UIS:IsKeyDown(Enum.KeyCode[KeyCodeName]) then
				local UpdateStateTick = Actions[ActionName]()--perform action
				if UpdateStateTick then
					StateTick = Now--last action changed right now
				end
				UpdateHumanoid()--update our character
			end
		end
	end
end

game["Run Service"].RenderStepped:Connect(ProcessInputState)--check inputs every frame

Result:

  • Able to handle state transitions with basic “if this go from this → that” logic
  • Able to handle cooldowns to prevent states from changing too quickly
  • Able to call actions from anywhere by using Example:Connect(ActionFunction) to make Gui buttons for you actions trivial

your code will be much easier to read, and your character state will be much easier to logic check and set (e.x jumping while prone makes you crouch, jumping again makes you stand up & crouching from a sprinting state results in a sliding state)

When you think about your character controls in this way adding movement mechanics becomes easy and logical, and not a jumbled mess of multiple scripts desperately trying to figure out what they’re allowed to do and not allowed to do/disabling eachother

this is just a basic example that doesn’t actually do anything, the idea I’m trying to present to you is the philosophy of designing movement mechanics for your game that is intuitive to you as the developer, and won’t result in you tearing your hair out later down the line trying to criss-cross all these different mechanics in seperate scripts and have scripts disabling eachother and other nonsense I see developers do on a daily basis.

you can also take it a step farther and use ModuleScripts to keep everything more organized and readable (that’s how Roblox does almost anything, not just their ControlScript)

Hope this advice will help you on your next character control system, or motivates you to rewrite the whole thing entirely. The sky is the limit! Good luck!

tl;dr: doing desired results directly in your input function is bad practice and makes your code harder to work with/read in the long run

5 Likes

Hi, My game doesn’t let you jump or sprint in the first place, so it’s kinda unnecessary to do this however I might take a look at that later when looking back at this and thanks for the help.

this just freezes the game, can you better explain this please?