class Chione::System

The System (behavior) class

Constants

DEFAULT_ASPECT_HASH

A Hash that auto-vivifies only its :default key

Attributes

aspect_entities[R]

The Hash of Sets of entity IDs which match the System's aspects, keyed by aspect name.

world[R]

The World which the System belongs to

Public Class Methods

aspect( name, *required, all_of: nil, one_of: nil, none_of: nil ) click to toggle source

Add the specified component_types to the Aspect of this System as being required in any entities it processes.

# File lib/chione/system.rb, line 55
def self::aspect( name, *required, all_of: nil, one_of: nil, none_of: nil )
        aspect = Chione::Aspect.new

        all_of = required + Array( all_of )

        aspect = aspect.with_all_of( all_of )
        aspect = aspect.with_one_of( one_of )   if one_of
        aspect = aspect.with_none_of( none_of ) if none_of

        self.aspects[ name ] = aspect
end
every_tick( &block ) click to toggle source

Declare a block that is called once every tick for each entity that matches the given aspect.

# File lib/chione/system.rb, line 97
def self::every_tick( &block )
        return self.on( 'timing' ) do |event_name, payload|
                self.instance_exec( *payload, &block )
        end
end
inherited( subclass ) click to toggle source

Add some per-subclass data structures to inheriting +subclass+es.

Calls superclass method
# File lib/chione/system.rb, line 105
def self::inherited( subclass )
        super
        subclass.instance_variable_set( :@aspects, DEFAULT_ASPECT_HASH.clone )
        subclass.instance_variable_set( :@event_handlers, self.event_handlers&.dup || [] )
        subclass.instance_variable_set( :@injected_systems, self.injected_systems&.dup || {} )
end
inject( *systems ) click to toggle source

Dependency-injection: declare one or more systems that should be passed to start by the running World.

# File lib/chione/system.rb, line 70
def self::inject( *systems )
        systems.each do |system_type|
                system_type = system_type.to_sym
                system_class = Chione::System.get_subclass( system_type )
                attr_accessor( "#{system_type}_system" )
                self.injected_systems[ system_type ] = system_class
        end
end
new( world, * ) click to toggle source

Create a new Chione::System for the specified world.

# File lib/chione/system.rb, line 114
def initialize( world, * )
        self.log.debug "Setting up %p" % [ self.class ]
        @world  = world
        @aspect_entities = self.class.aspects.each_with_object( {} ) do |(aspect_name, aspect), hash|
                matching_set = world.entities_with( aspect )
                self.log.debug "Initial Set with the %s aspect: %p" % [ aspect_name, matching_set]
                hash[ aspect_name ] = matching_set
        end
end
on( event_name, &block ) click to toggle source

Declare a block that is called once whenever an event matching event_name is broadcast to the World.

# File lib/chione/system.rb, line 82
def self::on( event_name, &block )
        raise LocalJumpError, "no block given" unless block
        raise ArgumentError, "callback has wrong arity" unless block.arity >= 2 || block.arity < 0

        method_name = "on_%s_event" % [ event_name.tr('/', '_') ]
        self.log.debug "Making handler method #%s for %s events out of %p" %
                [ method_name, event_name, block ]
        define_method( method_name, &block )

        self.event_handlers << [ event_name, method_name ]
end

Public Instance Methods

aspects() click to toggle source

The Hash of Chione::Aspects that describe entities this system is interested in, keyed by name (a Symbol). A System which declares no aspects will have a :default Aspect which matches all entities.

# File lib/chione/system.rb, line 41
singleton_attr_reader :aspects
entities( aspect_name=:default ) click to toggle source

Return an Enumerator that yields the entities which match the given aspect_name.

# File lib/chione/system.rb, line 167
def entities( aspect_name=:default )
        return self.aspect_entities[ aspect_name ].to_enum( :each )
end
entity_components_updated( entity_id, components_hash ) click to toggle source

Entity callback – called whenever an entity has a component added to it or removed from it. Calls the appropriate callback (inserted or removed) if the component change caused it to belong to or stop belonging to one of the system's aspects.

# File lib/chione/system.rb, line 176
def entity_components_updated( entity_id, components_hash )
        self.class.aspects.each do |aspect_name, aspect|
                entity_ids = self.aspect_entities[ aspect_name ]

                if aspect.matches?( components_hash )
                        self.inserted( aspect_name, entity_id, components_hash ) if
                                entity_ids.add?( entity_id )
                else
                        self.removed( aspect_name, entity_id, components_hash ) if
                                entity_ids.delete?( entity_id )
                end
        end
end
event_handlers() click to toggle source

Event handler tuples (event name, callback) that should be registered when the System is started.

# File lib/chione/system.rb, line 46
singleton_attr_reader :event_handlers
injected_systems() click to toggle source

Systems to be injected by the world when this System is started.

# File lib/chione/system.rb, line 50
singleton_attr_reader :injected_systems
inserted( aspect_name, entity_id, components ) click to toggle source

Entity callback – called whenever an entity has a component added to it that makes it start matching an aspect of the receiving System. The aspect_name is the name of the Aspect it now matches, and the components are a Hash of the entity's components keyed by Class. By default this is a no-op.

# File lib/chione/system.rb, line 196
def inserted( aspect_name, entity_id, components )
        self.log.debug "Entity %s now matches the %s aspect." % [ entity_id, aspect_name ]
end
removed( aspect_name, entity_id, components ) click to toggle source

Entity callback – called whenever an entity has a component removed from it that makes it stop matching an aspect of the receiving System. The aspect_name is the name of the Aspect it no longer matches, and the components are a Hash of the entity's components keyed by Class. By default this is a no-op.

# File lib/chione/system.rb, line 206
def removed( aspect_name, entity_id, components )
        self.log.debug "Entity %s no longer matches the %s aspect." % [ entity_id, aspect_name ]
end
start( **injected_systems ) click to toggle source

Start the system.

# File lib/chione/system.rb, line 139
def start( **injected_systems )
        self.log.info "Starting the %p system; %d injected systems, %d event handlers to register" %
                [ self.class, injected_systems.length, self.class.event_handlers.length ]

        injected_systems.each do |name, other_system|
                self.public_send( "#{name}_system=", other_system )
        end

        self.class.event_handlers.each do |event_name, method_name|
                callback = self.method( method_name )
                self.log.info "Registering %p as a callback for '%s' events." % [ callback, event_name ]
                self.world.subscribe( event_name, callback )
        end
end
stop() click to toggle source

Stop the system.

# File lib/chione/system.rb, line 156
def stop
        self.log.info "Stopping the %p system" % [ self.class ]
        self.class.event_handlers.each do |_, method_name|
                callback = self.method( method_name )
                self.log.info "Unregistering subscription for %p." % [ callback ]
                self.world.unsubscribe( callback )
        end
end

Protected Instance Methods

inspect_details() click to toggle source

Return the detail part of the inspection string.

# File lib/chione/system.rb, line 216
def inspect_details
        return "for %p:%#016x" % [ self.world.class, self.world.object_id * 2 ]
end