#==============================================================================
# ** Scheduler
#------------------------------------------------------------------------------
# This class allows to schedule a proc or method call a given amount of frames
# into the future with any amount of arguments
#==============================================================================
class Scheduler
#============================================================================
# ** Order
#----------------------------------------------------------------------------
# An order is a proc, method or something else which has 'call' as a method,
# and the arguments to pass along.
#============================================================================
# Create an struct for containing the data
Order = Struct.new(:callable, :arguments)
# Extend the class with a call-method which calls the callable with the args
class Order
#------------------------------------------------------------------------
# * Call the callable with the present arguments
#------------------------------------------------------------------------
def call
callable.call(*arguments)
end
end
#============================================================================
# ** RecurringOrder
#----------------------------------------------------------------------------
# An order which is recurring every specified amount of time until
# FalseClass is returned from the call.
# Note that arguments remain the same for each call
#============================================================================
# Create an struct for containing the data
RecurringOrder = Struct.new(:callable, :arguments, :frames)
# Extend the class with a call-method which calls the callable with the args
class RecurringOrder
#------------------------------------------------------------------------
# * Call the callable with the present arguments
#------------------------------------------------------------------------
def call
result = callable.call(*arguments)
unless result == FalseClass
Scheduler.schedule_recurring(frames, frames, callable, *arguments)
end
end
end
#============================================================================
# ** Mapping
#----------------------------------------------------------------------------
# Maps an index to an array. Values can be added to these value.
# Each array starts empty.
#============================================================================
class Mapping
#------------------------------------------------------------------------
# * Initialization
#------------------------------------------------------------------------
def initialize
@mapping = {}
end
#------------------------------------------------------------------------
# * Add an value to a given index
#------------------------------------------------------------------------
def add(index, value)
@mapping[index] = [] if @mapping[index].nil?
@mapping[index] << value
end
#------------------------------------------------------------------------
# * Retrieve the list of values mapped to the index
#------------------------------------------------------------------------
def get(index)
return [] if @mapping[index].nil?
@mapping[index]
end
#------------------------------------------------------------------------
# * Delete the array the index is mapped to. Conceptually it is now empty
#------------------------------------------------------------------------
def empty(index)
@mapping.delete(index)
end
end
#--------------------------------------------------------------------------
# * Initialization
#--------------------------------------------------------------------------
def initialize
# This maps
@mapping = Mapping.new
@tick = 0
end
#--------------------------------------------------------------------------
# * Scheduling
#--------------------------------------------------------------------------
def schedule(frames, callable, *arguments)
# Create an order
order = Order.new(callable, arguments)
@mapping.add(frames + @tick, order)
end
#--------------------------------------------------------------------------
# * Scheduling
#--------------------------------------------------------------------------
def schedule_recurring(frames, frames_to_wait, callable, *arguments)
# Create an order
order = RecurringOrder.new(callable, arguments, frames_to_wait)
@mapping.add(frames + @tick, order)
end
#--------------------------------------------------------------------------
# * Update the scheduler
#--------------------------------------------------------------------------
def update
# Get the orders for the current tick
orders = @mapping.get(@tick)
# Delete the mapping's reference to the list of orders
@mapping.empty(@tick)
# Call each order
for order in orders
order.call
end
# Advance the tick (next frame)
@tick += 1
end
#--------------------------------------------------------------------------
# * 'Singleton' principle used although you can easily make
# an extra scheduler. (Class method only works for this)
#--------------------------------------------------------------------------
@@instance = self.new
def self.instance
return @@instance
end
## Class methods point to the equivalent instance methods
def self.schedule_recurring(*args) instance.schedule_recurring(*args); end
def self.schedule(*args) instance.schedule(*args); end
def self.update(*args) instance.update(*args); end
end
module Graphics
class << self
unless self.method_defined?(:scheduler_update)
alias :scheduler_update :update
end
def update(*args)
scheduler_update(*args)
Scheduler.update
end
end
end