This scheduler uses the idea of a 'condition'. A coroutine will not be scheduled unless its condition is true. When a coroutine is first scheduled, it is typically given a 'true' condition and will execute in the next available slot. It may then, at any time, yield control, returning a new condition as part of the yield. If no such condition is returned, the coroutine will not be rescheduled.
The expectation is that helper functions like
WalkTo() will include yield operations that return appropriate conditions, and the script writer will never have to worry about explicit yields. The result is a system that, within certain bounds, just works the way you'd expect.
The code can be found in Files:wiki_insecure/users/twrensch/play.lua.
Here's the example (which is also included in the source file above):
-- Wait is a function that tells the scheduler to -- wait for some number of seconds before restarting -- the script. function wait(seconds, start) local t = (start or os.clock()) + seconds coroutine.yield( function() return os.clock() >= t end) end -- Two pretty much identical functions that differ -- only in the label they print and the amount of -- time they wait between prints. simsch.start( function () for i=1,10 do wait(1) print("One ", i) end end) simsch.start( function () for i=1,10 do wait(1.6) print("Two ", i) end end) -- Start it up simsch.run()
I imagine this being useful in scripting agents in games. For example, imagine I'm writing a script for my dog Rover. I want him to go to my home, fetch my Battle Axe and return. A script might look like this:
function Rover:fetchAxe() local location = whereAmI(self) Rover:walkTo(self.home) self:pickup(MyAxe) Rover:walkTo(location) self:drop() end
walkTo() function would include yields with appropriate condition arguments to deal with paths and delay time. Thus the effect would be that the script would take as much game and/or real time to execute as would be appropriate for the action, namely walking to home and back to where he started. A simple version of the
walkTo() function might simply wait an amount of time appropriate for the distance and the agent's speed:
function Agent:walkTo(there) local here = whereAmI(self) local distance = here:distanceTo(there) local arivalTime = now() + distance / self.speed coroutine.yield( function() return now() >= arivalTime end) end