2D movement script's performance is bad

i have been creating an arcade game, and i created all the scripts except for two. The 2d camera, and 2d movement from Gnomecode’s youtube tutorial. i recently realized after i fixed the camera script that the control script was not performing well. i would like if you could review this code and tell me what makes it so laggy.

local player = game.Players.LocalPlayer
local RunService = game:GetService("RunService")
local ContextActionService = game:GetService("ContextActionService")
local collection = game:GetService("CollectionService")
 
local jumping = false
local crouching = false
local already_destroyed = false
local leftValue, rightValue = 0, 0
 
local function onLeft(actionName, inputState)
	if inputState == Enum.UserInputState.Begin then	
		leftValue = 1
	elseif inputState == Enum.UserInputState.End then
		leftValue = 0
	end
end
 
local function onRight(actionName, inputState)
	if inputState == Enum.UserInputState.Begin then
		rightValue = 1
	elseif inputState == Enum.UserInputState.End then
		rightValue = 0
	end
end
 
local function onJump(actionName, inputState)
	if inputState == Enum.UserInputState.Begin then
		jumping = true
	elseif inputState == Enum.UserInputState.End then
		jumping = false
	end
end

local function onCrouch(actionName,inputState)
	if inputState == Enum.UserInputState.Begin then
		crouching = true
		already_destroyed = false
	end
	if inputState == Enum.UserInputState.End then
		crouching = false
	end
end
 
local function onUpdate()
	if player.Character and player.Character:FindFirstChild("Humanoid") then
		if jumping then
			player.Character.Humanoid.Jump = true
			crouching = false
		end
		if crouching then
			local id = "rbxassetid://5578912143"
			local anim = Instance.new("Animation")
			anim.AnimationId = id
			local loaded = player.Character.Humanoid:LoadAnimation(anim)
			loaded:Play()
			player.Character.Humanoid.WalkSpeed = 0
			collection:AddTag(player.Character,"crouching")
			RunService.Heartbeat:Connect(function()
				if not crouching then
					if player.Character.Humanoid.Health <1 then return end
					collection:RemoveTag(player.Character,"crouching")
					loaded:Stop()
					player.Character.Humanoid.WalkSpeed = 16
				end
			end)
		end
		local moveDirection = rightValue - leftValue
		player.Character.Humanoid:Move(Vector3.new(moveDirection,0,0), false)
	end
end
 
RunService:BindToRenderStep("Control", Enum.RenderPriority.Input.Value, onUpdate)
 
ContextActionService:BindAction("Left", onLeft, true, "A", Enum.KeyCode.DPadLeft,Enum.KeyCode.A)
ContextActionService:BindAction("Right", onRight, true, "D", Enum.KeyCode.DPadRight,Enum.KeyCode.D)
ContextActionService:BindAction("Jump", onJump, true, "W", Enum.KeyCode.W, Enum.KeyCode.Up, Enum.KeyCode.DPadUp, Enum.KeyCode.ButtonA)
ContextActionService:BindAction("crouch",onCrouch,true,"S",Enum.KeyCode.S)

please do not link me to gnomecodes’ tutorial as it is what’s causing the issue.

thank you for your time. :grinning:

1 Like

Could you please try to debug your own code to find out where the performance hits are going? You can use the MicroProfiler to get a sense of what processes are overperforming (the longer the bar the worse, be mindful of your zoom though) and some simple benchmarking to check how long it takes your code to run certain parts.

Example of how you might want to benchmark (please excuse the ugly syntax):

local function benchmark(label, callback, ...)
    local timeStart = os.clock()
    callback(...)
    local timeAfter = os.clock()
    print(label, "-", timeAfter - timeStart)
end

-- Example anonymous function benchmark
-- (please ignore ugly syntax)
benchmark("anonf", function(...)
    warn(...)
end, "foobar")

-- Example defined function benchmark
local function foobar(...)
    warn(...)
end

benchmark("foobar", foobar, "baz")

i’m not sure how the microprofiler works, or benchmarking. could you explain what the properties of benchmark are? label, callback, …

alright i think i found out… i believe it’s because its running the if statements and executing the code every single frame, but i’m not sure how to rewrite the if crouching parts to not run every single frame, but to instead only run when the crouching value is changed at first.

You are checking it every frame, do not expect it to run smoothly especially when you check this many things.

The only problem I see is the fact that you Instance an animation every single frame without destroy it afterwards or something, it should be binded to a callback, what’s worse is that you connected heartbeats to the rendersteps without ever disconnecting them. I see no reason here why you didnt use callback and did the constantly checking method.

Also Humanoid:LoadAnimation is deprecated.

where should i disconnect, and i had no idea Humanoid:LoadAnimation was deprecated. what should i use instead of it?

The idea is that the hearbeat loop shouldn’t even exist to begin with.

Humanoid.Animator is now the way to load animations

You can hook it to the onCrouch function instead of running that loop that checks every single frame.

what is it? particularly, the contextactionservice functions?

You can hook the check inside the wait for crouching end thing instead of running a loop that constantly check.
But again as mentioned you should not be running this loop nor this check inside the loop to begin with.

The onUpdate function should not contain the check and handle the crouch event, it should be handled on the onCrouch event

Now that I took more time to look at your script, I think that the entirety of the onUpdate shouldn’t even exist. While true loops like Heartbeats and the likes are expensive and should always be avoided if possible.

alright well, at the current state of the code all i can do is jump, no moving right nor left, or crouching.

local function onCrouch(actionName,inputState)
	if inputState == Enum.UserInputState.Begin then
		crouching = true
		already_destroyed = false
		local id = "rbxassetid://5578912143"
		local anim = Instance.new("Animation")
		anim.AnimationId = id
		local loaded = player.Character.Humanoid.Animator:LoadAnimation(anim)
		loaded:Play()
		player.Character.Humanoid.WalkSpeed = 0
		collection:AddTag(player.Character,"crouching")
	end
	if inputState == Enum.UserInputState.End then
		crouching = false
		collection:RemoveTag(player.Character,"crouching")
	--	loaded:Stop()
		player.Character.Humanoid.WalkSpeed = 16
	end
end
 
local function onUpdate()
	if player.Character and player.Character:FindFirstChild("Humanoid") then
	--[[if jumping then
			player.Character.Humanoid.Jump = true
			crouching = false
		end]]--
		
		--[[if crouching then
			local id = "rbxassetid://5578912143"
			local anim = Instance.new("Animation")
			anim.AnimationId = id
			local loaded = player.Character.Humanoid:LoadAnimation(anim)
			loaded:Play()
			player.Character.Humanoid.WalkSpeed = 0
			collection:AddTag(player.Character,"crouching")
		if not crouching then
			if player.Character.Humanoid.Health <1 then return end
				collection:RemoveTag(player.Character,"crouching")
				loaded:Stop()
				player.Character.Humanoid.WalkSpeed = 16
			end
		end]]--
			
		local moveDirection = rightValue - leftValue
		player.Character.Humanoid:Move(Vector3.new(moveDirection,0,0), false)
	end
end

--RunService:BindToRenderStep("Control", Enum.RenderPriority.Input.Value, onUpdate)
 
ContextActionService:BindAction("Left", onLeft, true, "A", Enum.KeyCode.DPadLeft,Enum.KeyCode.A)
ContextActionService:BindAction("Right", onRight, true, "D", Enum.KeyCode.DPadRight,Enum.KeyCode.D)
ContextActionService:BindAction("Jump", onJump, true, "W", Enum.KeyCode.W, Enum.KeyCode.Up, Enum.KeyCode.DPadUp, Enum.KeyCode.ButtonA)
ContextActionService:BindAction("crouch",onCrouch,true,"S",Enum.KeyCode.S)

this is because i deleted the runservice function, however i’m not sure how i can incorporate

local moveDirection = rightValue - leftValue
player.Character.Humanoid:Move(Vector3.new(moveDirection,0,0), false)

without the onupdate function.

Put them inside onLeft and onRight.

Also add a holder out of the function scope to hold the loaded value.

thank you for the help, it’s working all good and clean now.
once i start crouching i cannot stop the animation however, what is a holder?

local id = "rbxassetid://5578912143"
	local anim = Instance.new("Animation")
	anim.AnimationId = id
	local loaded = player.Character.Humanoid.Animator:LoadAnimation(anim)
	if inputState == Enum.UserInputState.Begin then
		crouching = true
		already_destroyed = false
		loaded:Play()
		player.Character.Humanoid.WalkSpeed = 0
		collection:AddTag(player.Character,"crouching")
	end
	if inputState == Enum.UserInputState.End then
		crouching = false
		collection:RemoveTag(player.Character,"crouching")
		loaded:Stop()
		player.Character.Humanoid.WalkSpeed = 16
	end

Add a holder.
Like this

local Holder

function()
    --Assign it here
end

Also don’t create an animation every single time. The animation only has to be loaded once per new Humanoid

like this?

local holder

function()
	local id = "rbxassetid://5578912143"
	local anim = Instance.new("Animation")
	anim.AnimationId = id
	local loaded = player.Character.Humanoid.Animator:LoadAnimation(anim)
end

More like this

local Holder
local id = "rbxassetid://5578912143"
local anim = Instance.new("Animation")
anim.AnimationId = id
Holder = player.Character.Humanoid.Animator:LoadAnimation(anim)

local function onCrouch(actionName,inputState)
	if inputState == Enum.UserInputState.Begin then
		crouching = true
		already_destroyed = false
		Holder:Play()
		player.Character.Humanoid.WalkSpeed = 0
		collection:AddTag(player.Character,"crouching")
	end
	if inputState == Enum.UserInputState.End then
		crouching = false
		collection:RemoveTag(player.Character,"crouching")
		Holder:Stop()
		player.Character.Humanoid.WalkSpeed = 16
	end
end

But of course, your final script should look a bit like this:

local anim = Instance.new("Animation")
anim.AnimationId = "rbxassetid://5578912143"
local AnimateTrack = player.Character.Humanoid.Animator:LoadAnimation(anim)

Don’t forget to reload the track every time the Humanoid dies!

1 Like

works! thanks for all the help :grinning: