lib/baku/entity_manager.rb in baku-0.1.0 vs lib/baku/entity_manager.rb in baku-0.2.0
- old
+ new
@@ -1,83 +1,83 @@
module Baku
+ # The EntityManager stores entities in such a way that they can be retrieved
+ # efficiently by either ComponentMask or tag. Before storing any entities, the
+ # ComponentMasks that we wish to match on should be registered. This step is
+ # performed transparently by the World whenever a System is added.
class EntityManager
def initialize
- @entities_by_system_mask = {}
+ @entities_by_component_mask = {}
@entities_by_tag = {}
-
- @component_set = Set.new
- @system_mask_cache = {}
end
- def register_entity(entity)
+ def register_component_mask(component_mask)
+ @entities_by_component_mask[component_mask] = []
+ end
+
+ def add_entity(entity)
+ add_entity_to_matching_component_lists(entity)
+
+ entity.add_event_listener(:component_added,
+ method(:on_entity_component_added))
+ entity.add_event_listener(:component_removed,
+ method(:on_entity_component_removed))
+
entity.tags.each do |tag|
@entities_by_tag[tag] ||= []
@entities_by_tag[tag] << entity
end
end
- def register_system(system)
- system.components.each do |component|
- @component_set << component
+ def remove_entity(entity)
+ entity.tags.each do |tag|
+ @entities_by_tag[tag].delete(entity)
end
-
- system_component_mask =
- get_component_mask(system.components)
-
- @system_mask_cache[system] = system_component_mask
- @entities_by_system_mask[system_component_mask] = []
- end
-
- # TODO: there may be a more efficent way to do this, like by comparing
- # the diff of the mask before and after, but this works for now.
- def entity_add_component(entity, component)
- old_mask = get_component_mask(entity.components)
- entity.components[component.class] = component
- new_mask = get_component_mask(entity.components)
+ entity.remove_event_listener(:component_added,
+ method(:on_entity_component_added))
+ entity.remove_event_listener(:component_removed,
+ method(:on_entity_component_removed))
- update_system_membership(entity, old_mask, new_mask)
+ @entities_by_component_mask.each do |component_mask, entities|
+ if component_mask.matches?(entity.component_mask)
+ entities.delete(entity)
+ end
+ end
end
- def entity_remove_component(entity, component)
- old_mask = get_component_mask(entity.components)
- entity.components.delete(component.class)
- new_mask = get_component_mask(entity.components)
-
- update_system_membership(entity, old_mask, new_mask)
+ def get_entities(component_mask)
+ @entities_by_component_mask[component_mask]
end
- def get_entities_for_system(system)
- system_mask = @system_mask_cache[system]
- @entities_by_system_mask[system_mask]
- end
-
def get_entities_by_tag(tag)
@entities_by_tag[tag]
end
private
- def get_component_mask(components)
- mask = 0
-
- @component_set.each_with_index do |c, i|
- mask |= (1 << i) if components.include?(c)
+ def add_entity_to_matching_component_lists(entity)
+ @entities_by_component_mask.each do |component_mask, entities|
+ if component_mask.matches?(entity.component_mask)
+ entities << entity
+ end
end
+ end
- mask
+ def on_entity_component_added(entity, component)
+ add_entity_to_matching_component_lists(entity)
end
- def update_system_membership(entity, old_mask, new_mask)
- @entities_by_system_mask.each do |system_mask, entities|
- old_match = (system_mask & old_mask == system_mask)
- new_match = (system_mask & new_mask == system_mask)
+ def on_entity_component_removed(entity, component)
+ old_mask = ComponentMask.from_components(entity.components + component)
+ new_mask = entity.component_mask
+
+ @entities_by_component_mask.each do |component_mask, entities|
+ old_match = component_mask.match?(old_mask)
+ new_match = component_mask.match?(new_mask)
if old_match && !new_match
entities.delete(entity)
- elsif !old_match && new_match
- entities << entity
end
- end
+ end
end
end
end