Situation Scheduler

lua-users home
wiki

Quite some time ago I posted a simple cooperative multitasking scheduler using coroutines to the list. This is a variation of that scheduler that should work well for simple simulation and game scripting.

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 wait() or 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

Here, the 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


RecentChanges · preferences
edit · history
Last edited January 19, 2004 8:12 pm GMT (diff)