Frame Animation Loop support, what function should I use?

I’m hoping to achieve a way to start animation frame loops and stop them when inputs are stopped.
How I have it now, the frames loop from a while loop that tests for the inputs and when there isn’t any, the loop will stop and it’ll display the unmoving image.

while wait() do
	if dir1 or dir2 then
		for i,v in pairs(frameInfo) do
			wait(frameDelay)
			characterLabel.Image = v
		end
	else
		characterLabel.Image = stillFrame
	end
end

And I know this is a terribly inefficient way to do it but I couldn’t think of another way that worked in testing. I’ve tried using other types of loops, read about coroutine and spawn things but I couldn’t get that working. The closest thing I think that could suit my needs would be using the coroutine:yield() when the inputs stop but I can’t start the loop function in the first place at least with how much I know currently.

Any help would be greatly appreciated, thank you!

1 Like

Another issue with this method I’m using now is that the frames will continue to the end of the animation loop to stop. I was hoping if anyone out there knows more about coroutines than me would know if using coroutines would remedy this also.

1 Like

Not quite sure I understand what you’re trying to achieve or fix but couldn’t you just add an if statement within the actual for loop (not the while loop). That way every time it runs, it would check to see if a certain value is true and you go from there.

For example, something like this:

Note the below is just a rough draft to give you an idea, it may have typos, etc.

local canAnimate = true

function animateFrame(frameInfo)
	for i, v in pairs(frameInfo) do
		if canAnimate then -- Check if it can animate and if true allows the animation to continue
			wait(frameDelay)
			characterLabel.Image = v
		else -- If false, the animation will default to this
			characterLabel.Image = stillFrame
		end;
	end;
end;

-- Lets pretend the user input starts
canAnimate = true
animateFrame(theFrameInfo)

-- Lets pretend the user input stops
canAnimate = false -- If the loop is still running it should turn back to stillFrame instead of animating
characterLabel.Image = stillFrame 

If this isn’t what you wanted, could please send a gif of how its currently working so I can get a better idea of what you need.

1 Like
local uis = game:GetService("UserInputService")
local run = game:GetService("RunService")

local character = script.Parent
local characterLabel = character:FindFirstChild("HumanoidRootPart").SurfaceGui.characterLabel
local keybinds = {
	[Enum.KeyCode.W] = "up";
	[Enum.KeyCode.S] = "down";
	[Enum.KeyCode.A] = "left";
	[Enum.KeyCode.D] = "right";
}

local prefix = "http://www.roblox.com/asset/?id="
local stillFrame = prefix.."----"
local frameInfo = {
	prefix.."----";
	prefix.."----";
	prefix.."----";
	prefix.."----";
}
local frameDelay = 0.1

local dir1 = nil
local dir2 = nil

uis.InputBegan:Connect(function(data)
	local var = keybinds[data.KeyCode]
	if var == "up" then
		if dir1 ~= "up" then
			if dir1 == nil then
				dir1 = "up"
			else
				dir2 = "up"
			end
		end
	elseif var == "down" then
		if dir1 ~= "down" then
			if dir1 == nil then
				dir1 = "down"
			else
				dir2 = "down"
			end
		end
	elseif var == "left" then
		if dir1 ~= "left" then
			if dir1 == nil then
				dir1 = "left"
			else
				dir2 = "left"
			end
		end
	elseif var == "right" then
		if dir1 ~= "right" then
			if dir1 == nil then
				dir1 = "right"
			else
				dir2 = "right"
			end
		end
	end
end)
uis.InputEnded:Connect(function(data)
	local var = keybinds[data.KeyCode]
	if var == "up" then
		if dir1 == "up" then
			dir1 = nil
		elseif dir2 == "up" then
			dir2 = nil
		end
	end
	if var == "down" then
		if dir1 == "down" then
			dir1 = nil
		elseif dir2 == "down" then
			dir2 = nil
		end
	end
	if var == "left" then
		if dir1 == "left" then
			dir1 = nil
		elseif dir2 == "left" then
			dir2 = nil
		end
	end
	if var == "right" then
		if dir1 == "right" then
			dir1 = nil
		elseif dir2 == "right" then
			dir2 = nil
		end
	end
end) 

local walking
run.RenderStepped:Connect(function()
	if dir1 or dir2 then
		walking = true
		
		if dir1 == "up" or dir1 == "down" then
			if dir2 == "up" or dir2 == "down" then
				walking = false
			end
		elseif dir1 == "left" or dir1 == "right" then
			if dir2 == "left" or dir2 == "right" then
				walking = false
			end
		end
	else
		walking = false
	end
	
	print(walking)
end)

If it helps, this is my current layout for the script. Basically, the player’s given two available movement slots, dir1 and dir2. This is to keep the animation going if two keys are pressed at the same time and then it switches to only one key.

I already have everything working how I want it, the print in the run.RenderStepped is giving me all the values I want consistently and all I need to do now is convert that bool into the status or cycle or the animation loop. Hopefully, if the player stops the anim will stop and reset but if they hold it for longer, it will stay with the bool value and keep looping.

If I’m understanding you correctly than you should be able to use your while loop but instead add an if statement for the walking bool.

Like so:

while wait() do
	if dir1 or dir2 then
		for i,v in pairs(frameInfo) do
			if walking == true then -- If player is walking than continue animation
				wait(frameDelay)
				characterLabel.Image = v
			else -- If player isn't walking revert to still frame
				characterLabel.Image = stillFrame
			end;
		end
	else
		characterLabel.Image = stillFrame
	end
end