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