This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Cranium's profile picture

Proof of concept help, with parallel API.

Started by Cranium, 03 August 2012 - 11:10 PM
Cranium #1
Posted 04 August 2012 - 01:10 AM
I have been trying to complete a proof of concept, whereas a user could have an animated menu, while it is waiting for an input from the user. So far, I have it waiting for an input just fine, but I have been having problems with it trying to execute other code, since for an animation to work, I need for the first animation to loop. My goal with the proof of concept is to have a character, in this case Kirby, enter, and then wait in the middle of the screen for the user input. I have only one command to give Kirby at this time, and that is to DANCE! Problem is, when I give him the dance command, the idle command is still running due to the parallel API. Here is the code I have so far, and much of it has been generously worked on by the other members of the Ask a Pro section:

-- screen functions
function border()
local w, h = term.getSize()
local s = "+"..string.rep("-", w - 2).."+"
term.setCursorPos(1, 1)
term.write(s)
for y = 2, h - 1 do
  term.setCursorPos(1, y)
  term.write("|")
  term.setCursorPos(w, y)
  term.write("|")
end
term.setCursorPos(1, h)
term.write(s)
end
function kirbyEnter()
local mY = mY/2
term.setCursorPos(2,mY)
write(">")
term.setCursorPos(2,mY)
sleep(.2)
write("')>")
term.setCursorPos(2,mY)
sleep(.2)
write(".')>")
term.setCursorPos(2,mY)
sleep(.2)
write("('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("<('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("  ( V') ")
term.setCursorPos(2,mY)
sleep(.2)
write("  <(   )>")
term.setCursorPos(2,mY)
sleep(.2)
write("    ('V )")
term.setCursorPos(2,mY)
sleep(.2)
write("    <('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("	  ( V')")
term.setCursorPos(2,mY)
sleep(.2)
write("	   <(   )>")
term.setCursorPos(2,mY)
sleep(.2)
write("		 ('V )")
term.setCursorPos(2,mY)
sleep(.2)
write("		 <('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("		   ( V')")
term.setCursorPos(2,mY)
sleep(.2)
write("		   <(   )>")
term.setCursorPos(2,mY)
sleep(.2)
write("			 ('V )")
term.setCursorPos(2,mY)
sleep(.2)
write("			 <('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("			   ( V')")
term.setCursorPos(2,mY)
sleep(.2)
write("			   <(   )>")
term.setCursorPos(2,mY)
sleep(.2)
write("				 ('V )")
term.setCursorPos(2,mY)
sleep(.2)
write("				 <('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("				  <('.')>")
term.setCursorPos(2,mY)
sleep(.2)
write("				   <('.')>")
end
function kirbyDance(mX,mY)
local mX = mX/2
local mY = mY/2
term.setCursorPos(mX - 4,mY)
write("^('.')>")
sleep(.5)
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("<('.')^")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("^('.')>")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("<('.')^")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("^('.')>")
term.setCursorPos(mX - 4 ,mY)
sleep(.5)
write("<('.')^")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write(" (>'.')>")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("<('.'<) ")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write(" (>'.')>")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("<('.'<) ")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write(" (>'.')>")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("<('.'<) ")
term.setCursorPos(mX - 4,mY)
sleep(.5)
write("<('.')> ")
sleep(.5)
term.setCursorPos(mX - 4,mY)
end
function select()
term.setCursorPos(2,10)
write("Make your selection")
term.setCursorPos(2,12)
write("Dance")
term.setCursorPos(2,17)
write("Selection: ")
--other options available in the future
  local input = read()
  if input == "dance" then
    kirbyDance(mX, mY)
  else
    print("INVALID")
    term.clear()
    border()
    select()
  end
end
function kirbyIdle()
local mX = mX/2
local mY = mY/2
while true do
term.setCursorPos(mX - 4,mY)
write("<('.')>")
sleep(5)
term.setCursorPos(mX - 4,mY)
write("<(-.-)>")
sleep(.5)
end
end

-- end screen functions
mX, mY = term.getSize()
term.clear()
border()
kirbyEnter()
parallel.waitForAny(kirbyIdle,select)
So far, I only want this to run once. Waiting for the input, and then just stopping.
MysticT #2
Posted 04 August 2012 - 01:36 AM
Well, I guess you could break the menu/selection loop, so the parallel call will return, then you use the selection from the menu to run the corresponding function. Put that in a loop and it should work. But there's an easier way: don't use parallel. Use another menu that doesn't call read, so you can simply use events. I'll work on it and post what I get.
BigSHinyToys #3
Posted 04 August 2012 - 01:56 AM
I have made some modifications to your code fixed part of the animation and set up some control functions Please try this.
Spoiler

local bIsDancing = false
local termX,termY = 1,1
-- screen functions
function border()
    local w, h = term.getSize()
    local s = "+"..string.rep("-", w - 2).."+"
    term.setCursorPos(1, 1)
    term.write(s)
    for y = 2, h - 1 do
	    term.setCursorPos(1, y)
	    term.write("|")
	    term.setCursorPos(w, y)
	    term.write("|")
    end
    term.setCursorPos(1, h)
    term.write(s)
end
function kirbyEnter()
    local mY = mY/2
    term.setCursorPos(2,mY)
    write(">")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write(".')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("<('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("  ( V') ")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("  <(   )>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("    ('V )")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("    <('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("   ( V')   ")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("    <(   )>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("		  ('V )")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("		  <('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("		    ( V')")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("		    <(   )>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("				  ('V )")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("				  <('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("				    ( V')")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("				    <(   )>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("						  ('V )")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("						  <('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("						   <('.')>")
    term.setCursorPos(2,mY)
    sleep(.2)
    write("						    <('.')>")
end
function kirbyDance(mX,mY)
    local mX = mX/2
    local mY = mY/2
    term.setCursorPos(mX - 4,mY)
    write("^('.')>")
    sleep(.5)
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("<('.')^")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("^('.')>")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("<('.')^")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("^('.')>")
    term.setCursorPos(mX - 4 ,mY)
    sleep(.5)
    write("<('.')^")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write(" (>'.')>")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("<('.'<) ")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write(" (>'.')>")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("<('.'<) ")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write(" (>'.')>")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("<('.'<) ")
    term.setCursorPos(mX - 4,mY)
    sleep(.5)
    write("<('.')> ")
    sleep(.5)
    term.setCursorPos(mX - 4,mY)
end
function select()
    term.setCursorPos(2,10)
    write("Make your selection")
    term.setCursorPos(2,12)
    write("Dance")
    term.setCursorPos(2,17)
    term.clearLine()
    write("Selection: ")
    --other options available in the future
    local input = read()
    if input == "dance" then
	    bIsDancing = true
	    kirbyDance(mX, mY)
	    bIsDancing = false
    else
	    print("INVALID")
    end
end
function SelectControl()
    while true do
	    select()
    end
end
function BorderControl() --lol
    while true do
	    termX,termY = term.getCursorPos()
	    border()
	    term.setCursorPos(termX,termY)
	    coroutine.yield()
    end
end
function kirbyIdle()
    local mX = mX/2
    local mY = mY/2
    while true do
	    if not bIsDancing then
		    termX,termY = term.getCursorPos()
		    term.setCursorPos(mX - 4,mY)
		    term.clearLine()
		    write("<('.')>")
		    term.setCursorPos(termX,termY)
	    end
	    sleep(5)
	    if not bIsDancing then
		    termX,termY = term.getCursorPos()
		    term.setCursorPos(mX - 4,mY)
		    term.clearLine()
		    write("<(-.-)>")
		    term.setCursorPos(termX,termY)
	    end
	    sleep(.5)
    end
end
-- end screen functions
mX, mY = term.getSize()
term.clear()
border()
kirbyEnter()
parallel.waitForAny(kirbyIdle,SelectControl,BorderControl)
Cranium #4
Posted 04 August 2012 - 02:11 AM
I have made some modifications to your code fixed part of the animation and set up some control functions Please try this.
Spoiler

local bIsDancing = false
local termX,termY = 1,1
-- screen functions
function border()
	local w, h = term.getSize()
	local s = "+"..string.rep("-", w - 2).."+"
	term.setCursorPos(1, 1)
	term.write(s)
	for y = 2, h - 1 do
		term.setCursorPos(1, y)
		term.write("|")
		term.setCursorPos(w, y)
		term.write("|")
	end
	term.setCursorPos(1, h)
	term.write(s)
end
function kirbyEnter()
	local mY = mY/2
	term.setCursorPos(2,mY)
	write(">")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write(".')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("<('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("  ( V') ")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("  <(   )>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("	('V )")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("	<('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("   ( V')   ")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("	<(   )>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("		  ('V )")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("		  <('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("			( V')")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("			<(   )>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("				  ('V )")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("				  <('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("					( V')")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("					<(   )>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("						  ('V )")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("						  <('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("						   <('.')>")
	term.setCursorPos(2,mY)
	sleep(.2)
	write("							<('.')>")
end
function kirbyDance(mX,mY)
	local mX = mX/2
	local mY = mY/2
	term.setCursorPos(mX - 4,mY)
	write("^('.')>")
	sleep(.5)
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("<('.')^")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("^('.')>")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("<('.')^")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("^('.')>")
	term.setCursorPos(mX - 4 ,mY)
	sleep(.5)
	write("<('.')^")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write(" (>'.')>")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("<('.'<) ")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write(" (>'.')>")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("<('.'<) ")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write(" (>'.')>")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("<('.'<) ")
	term.setCursorPos(mX - 4,mY)
	sleep(.5)
	write("<('.')> ")
	sleep(.5)
	term.setCursorPos(mX - 4,mY)
end
function select()
	term.setCursorPos(2,10)
	write("Make your selection")
	term.setCursorPos(2,12)
	write("Dance")
	term.setCursorPos(2,17)
	term.clearLine()
	write("Selection: ")
	--other options available in the future
	local input = read()
	if input == "dance" then
		bIsDancing = true
		kirbyDance(mX, mY)
		bIsDancing = false
	else
		print("INVALID")
	end
end
function SelectControl()
	while true do
		select()
	end
end
function BorderControl() --lol
	while true do
		termX,termY = term.getCursorPos()
		border()
		term.setCursorPos(termX,termY)
		coroutine.yield()
	end
end
function kirbyIdle()
	local mX = mX/2
	local mY = mY/2
	while true do
		if not bIsDancing then
			termX,termY = term.getCursorPos()
			term.setCursorPos(mX - 4,mY)
			term.clearLine()
			write("<('.')>")
			term.setCursorPos(termX,termY)
		end
		sleep(5)
		if not bIsDancing then
			termX,termY = term.getCursorPos()
			term.setCursorPos(mX - 4,mY)
			term.clearLine()
			write("<(-.-)>")
			term.setCursorPos(termX,termY)
		end
		sleep(.5)
	end
end
-- end screen functions
mX, mY = term.getSize()
term.clear()
border()
kirbyEnter()
parallel.waitForAny(kirbyIdle,SelectControl,BorderControl)
Ok, you totally fixed it!!! Now I just have to have Kirby dance a little better!
MysticT #5
Posted 04 August 2012 - 02:17 AM
Ok, a little late but here's what I have:
Spoiler

local tEnterAnimation = {
">",
"')>",
".')>",
"('.')>",
"<('.')>",
"  ( V') ",
"  <(   )>",
"    ('V )",
"    <('.')>",
"   ( V')",
"    <(   )>",
"		  ('V )",
"		  <('.')>",
"		    ( V')",
"		    <(   )>",
"				  ('V )",
"				  <('.')>",
"				    ( V')",
"				    <(   )>",
"						  ('V )",
"						  <('.')>",
"						   <('.')>",
"						    <('.')>"
}

local tDanceAnimation = {
"^('.')>",
"<('.')^",
"^('.')>",
"<('.')^",
"^('.')>",
"<('.')^",
" (>'.')>",
"<('.'<) ",
" (>'.')>",
"<('.'<) ",
" (>'.')>",
"<('.'<) ",
"<('.')> "
}

local tIdleAnimation = {
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<(-.-)>"
}

local function clear()
    term.clear()
    term.setCursorPos(1, 1)
end

local function drawAnimation(t)
    for _,s in ipairs(t) do
        clear()
        write(s)
        sleep(0.2)
    end
end

local nFrame = 1

local function drawIdleAnimation()
    term.setCursorPos(1, 1)
    term.clearLine()
    write(tIdleAnimation[nFrame])
end

local bExit = false

local tOptions = {
"Dance",
"Exit"
}

local tActions = {
function()
    drawAnimation(tDanceAnimation)
end,
function()
    bExit = true
end
}

local nSelected = 1

local function redrawMenu()
    term.setCursorPos(1, 2)
    for i, s in ipairs(tOptions) do
        if i == nSelected then
            print(">", s)
        else
            print(" ", s)
        end
    end
end

local function keyPressed(key)
    if key == 208 then -- Down
        if nSelected < #tOptions then
            nSelected = nSelected + 1
        else
            nSelected = 1
        end
    elseif key == 200 then -- Up
        if nSelected > 1 then
            nSelected = nSelected - 1
        else
            nSelected = #tOptions
        end
    elseif key == 28 then -- Enter
        tActions[nSelected]()
    end
end

drawAnimation(tEnterAnimation)
clear()

local timer = os.startTimer(0.5)

while not bExit do
    clear()
    drawIdleAnimation()
    redrawMenu()
    local evt, arg = os.pullEvent()
    if evt == "key" then
        keyPressed(arg)
    elseif evt == "timer" then
        nFrame = nFrame + 1
        if nFrame > #tIdleAnimation then
            nFrame = 1
        end
        timer = os.startTimer(0.5)
    end
end
clear()
It uses another menu, so it doesn't need parallel, and the animations are easier to change. I tested it and works fine, although I'm not sure if the enter animation should look like that :P/>/>
BigSHinyToys #6
Posted 04 August 2012 - 02:25 AM
Ok, a little late but here's what I have:
– snip –
It uses another menu, so it doesn't need parallel, and the animations are easier to change. I tested it and works fine, although I'm not sure if the enter animation should look like that :P/>/>
I always find it interesting our differing philosophies I try to work with the provided code as much as possible and you make the best possible solution to the problem demonstrated very well in our codes above.
Cranium #7
Posted 04 August 2012 - 02:30 AM
MysticT, I only have one question about your code:
What is the _,s in the drawAnimation() function, and what does it do? I have never seen that before.
MysticT #8
Posted 04 August 2012 - 02:32 AM
MysticT, I only have one question about your code:
What is the _,s in the drawAnimation() function, and what does it do? I have never seen that before.
It's just some variables used in the for loop. The _ is used normally to name variables that you don't use.
Cranium #9
Posted 04 August 2012 - 02:40 AM
Ok, that's neat. BTW, the code you have is great, but it did not keep looping the idle after giving the initial command. Any way around this?
MysticT #10
Posted 04 August 2012 - 02:45 AM
Did you try it? The idle animation works fine for me, even after doing the dance.
Cranium #11
Posted 04 August 2012 - 02:49 AM
Yeah, when I hit enter to select dance, he just stays there after dancing. No more blinking eyes…

Edit: I am using a CC emulator…if that means anything. I'm using this one.
BigSHinyToys #12
Posted 04 August 2012 - 02:52 AM
Did you try it? The idle animation works fine for me, even after doing the dance.
I tested it and I have same problem animation doesn't play because timer event occurs during animation meaning it ends the timer loop
BigSHinyToys #13
Posted 04 August 2012 - 02:55 AM
fixed MysticT's code
Spoiler

local tEnterAnimation = {
">",
"')>",
".')>",
"('.')>",
"<('.')>",
"  ( V') ",
"  <(   )>",
"    ('V )",
"    <('.')>",
"   ( V')",
"    <(   )>",
"				 ('V )",
"				 <('.')>",
"				   ( V')",
"				   <(   )>",
"								 ('V )",
"								 <('.')>",
"								   ( V')",
"								   <(   )>",
"												 ('V )",
"												 <('.')>",
"												  <('.')>",
"												   <('.')>"
}
local tDanceAnimation = {
"^('.')>",
"<('.')^",
"^('.')>",
"<('.')^",
"^('.')>",
"<('.')^",
" (>'.')>",
"<('.'<) ",
" (>'.')>",
"<('.'<) ",
" (>'.')>",
"<('.'<) ",
"<('.')> "
}
local tIdleAnimation = {
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<(-.-)>"
}
local function clear()
    term.clear()
    term.setCursorPos(1, 1)
end
local function drawAnimation(t)
    for _,s in ipairs(t) do
	    clear()
	    write(s)
	    sleep(0.2)
    end
end
local nFrame = 1
local function drawIdleAnimation()
    term.setCursorPos(1, 1)
    term.clearLine()
    write(tIdleAnimation[nFrame])
end
local bExit = false
local tOptions = {
"Dance",
"Exit"
}
local tActions = {
function()
    drawAnimation(tDanceAnimation)
end,
function()
    bExit = true
end
}
local nSelected = 1
local function redrawMenu()
    term.setCursorPos(1, 2)
    for i, s in ipairs(tOptions) do
	    if i == nSelected then
		    print(">", s)
	    else
		    print(" ", s)
	    end
    end
end
local function keyPressed(key)
    if key == 208 then -- Down
	    if nSelected < #tOptions then
		    nSelected = nSelected + 1
	    else
		    nSelected = 1
	    end
    elseif key == 200 then -- Up
	    if nSelected > 1 then
		    nSelected = nSelected - 1
	    else
		    nSelected = #tOptions
	    end
    elseif key == 28 then -- Enter
	    tActions[nSelected]()
    end
end
drawAnimation(tEnterAnimation)
clear()
local timer = os.startTimer(0.5)
while not bExit do
    clear()
    drawIdleAnimation()
    redrawMenu()
    local evt, arg = os.pullEvent()
    if evt == "key" then
	    keyPressed(arg)
  timer = os.startTimer(0.5)
    elseif evt == "timer" then
	    nFrame = nFrame + 1
	    if nFrame > #tIdleAnimation then
		    nFrame = 1
	    end
	    timer = os.startTimer(0.5)
    end
end
clear()
MysticT #14
Posted 04 August 2012 - 02:55 AM
Hmm, you'r right, I forgot to reset the timer. This should work:
Spoiler

local tEnterAnimation = {
">",
"')>",
".')>",
"('.')>",
"<('.')>",
"  ( V') ",
"  <(   )>",
"	('V )",
"	<('.')>",
"   ( V')",
"	<(   )>",
"		  ('V )",
"		  <('.')>",
"			( V')",
"			<(   )>",
"				  ('V )",
"				  <('.')>",
"					( V')",
"					<(   )>",
"						  ('V )",
"						  <('.')>",
"						   <('.')>",
"							<('.')>"
}

local tDanceAnimation = {
"^('.')>",
"<('.')^",
"^('.')>",
"<('.')^",
"^('.')>",
"<('.')^",
" (>'.')>",
"<('.'<) ",
" (>'.')>",
"<('.'<) ",
" (>'.')>",
"<('.'<) ",
"<('.')> "
}

local tIdleAnimation = {
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<('.')>",
"<(-.-)>"
}

local function clear()
	term.clear()
	term.setCursorPos(1, 1)
end

local function drawAnimation(t)
	for _,s in ipairs(t) do
		clear()
		write(s)
		sleep(0.2)
	end
end

local nFrame = 1

local function drawIdleAnimation()
	term.setCursorPos(1, 1)
	term.clearLine()
	write(tIdleAnimation[nFrame])
end

local bExit = false

local tOptions = {
"Dance",
"Exit"
}

local tActions = {
function()
	drawAnimation(tDanceAnimation)
end,
function()
	bExit = true
end
}

local nSelected = 1

local function redrawMenu()
	term.setCursorPos(1, 2)
	for i, s in ipairs(tOptions) do
		if i == nSelected then
			print(">", s)
		else
			print(" ", s)
		end
	end
end

local timer

local function keyPressed(key)
	if key == 208 then -- Down
		if nSelected < #tOptions then
			nSelected = nSelected + 1
		else
			nSelected = 1
		end
	elseif key == 200 then -- Up
		if nSelected > 1 then
			nSelected = nSelected - 1
		else
			nSelected = #tOptions
		end
	elseif key == 28 then -- Enter
		tActions[nSelected]()
		timer = os.startTimer(0.5)
	end
end

drawAnimation(tEnterAnimation)
clear()

timer = os.startTimer(0.5)

while not bExit do
	clear()
	drawIdleAnimation()
	redrawMenu()
	local evt, arg = os.pullEvent()
	if evt == "key" then
		keyPressed(arg)
	elseif evt == "timer" then
		nFrame = nFrame + 1
		if nFrame > #tIdleAnimation then
			nFrame = 1
		end
		timer = os.startTimer(0.5)
	end
end
clear()


fixed MysticT's code
– snip –
That would work, but it would reset the timer each time you press a key, so the idle animation wouldn't work correctly.