lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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.