[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Looking for examples: animation with coroutines
- From: Steven Johnson <steve@...>
- Date: Fri, 1 Feb 2013 18:13:27 -0600
Hi, Peter.
If your use case is as simple as the rabbit, then the timer is
probably the better option. But in more interesting cases you'll
probably have some state to track, along with more complex behaviors.
Say the carrot got moved around every now and then, the rabbit got
tired and took breaks, or was waiting for the wolf to disappear, and
so on. This can be a little (or a lot!) easier to manage via
coroutines than through a big state machine.
Typically you might build up some primitives based on whatever you do
often and to hide all the plumbing, e.g. (untested):
function Wait (time_lapse, update)
local now = GetCurrentTime() -- some time function, os.time or
whatever, in whatever units you're using
local last = now
while true do
local current = GetCurrentTime()
if current - now >= time_lapse then
break
else
if update then -- Call an update between yields, if desired
update(current - last)
end
coroutine.yield()
end
last = current
end
end
function WaitUntil (func, update)
while not func() do
if update then -- Same thing... could be folded into update too
update()
end
coroutine.yield()
end
end
-- And then, using the timer example from before...
setTimer(coroutine.wrap(function()
local rabbit = PutRabbitSomewhere()
local carrot = PutCarrotSomewhere()
-- Move the carrot every so often
setTimer(function()
if carrot.consumed then
return "cancel"
end
carrot:PutSomewhereElse()
end, 10000, "repeating")
-- Chase the carrot until it's been consumed
WaitUntil(function()
return carrot.consumed
end, function()
local time = math.random(3500, 5000) -- The average time a rabbit
will chase a carrot before getting bored
Wait(time, function(dt) -- Chase the carrot
rabbit:Approach(carrot, dt)
if Close(rabbit, carrot) then
carrot.consumed = true
end
end)
Wait(math.random(500, 1500) -- Take a break
end)
end), 100, "repeating")
You can also invert the control flow a bit, say by yielding inside a
callback. I do something like that to draw a Hilbert curve inside an
incremental algorithm (uses Corona SDK):
https://github.com/ggcrunchy/corona-sdk-snippets/blob/master/samples/Hilbert.lua
https://github.com/ggcrunchy/corona-sdk-snippets/blob/master/fill/Hilbert.lua#L103
Updating a textbox, some number of characters per unit of time, as
they're being parsed (old version of Love, haven't updated it):
https://github.com/ggcrunchy/Old-Love2D-Demo/blob/master/Scripts/Class/UI/Widget/Textbox.lua#L30
These aren't great examples, but if you can run the Corona snippets,
there's some coroutine-driven movement going on (in the Wrap'd timers)
in these two samples:
https://github.com/ggcrunchy/corona-sdk-snippets/blob/master/samples/Hop.lua#L237
https://github.com/ggcrunchy/corona-sdk-snippets/blob/master/samples/Timers.lua#L125
There's some more stuff in that repository if you search for "flow_ops".
Hope that helps.