summaryrefslogtreecommitdiffhomepage
path: root/lib/felflame/entity_manager.rb
blob: 74fc4c3d870e6071f3c58388a2f54d44024b7211 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
class FelFlame
  class Entities
    # Holds the unique ID of this entity
    # @return [Integer]
    attr_reader :id

    # A seperate attr_writer was made for documentation readability reasons.
    # Yard will list attr_reader is readonly which is my intention.
    # This value needs to be changable as it is set by other functions.
    # @!visibility private
    attr_writer :id

    # Creating a new Entity
    # @param components [Components] Can be any number of components, identical duplicates will be automatically purged however different components from the same component manager are allowed.
    # @return [Entity]
    def initialize(*components)
      # Assign new unique ID
      new_id = self.class.data.find_index(&:nil?)
      new_id = self.class.data.size if new_id.nil?
      self.id = new_id

      # Add each component
      add(*components)

      self.class.data[id] = self
    end

    # A hash that uses component manager constant names as keys, and where the values of those keys are arrays that contain the {FelFlame::ComponentManager#id IDs} of the components attached to this entity.
    # @return [Hash<Component_Manager, Array<Integer>>]
    def components
      @components ||= {}
    end

    # An alias for the {#id ID reader}
    # @return [Integer]
    def to_i
      id
    end

    # Removes this Entity from the list and purges all references to this Entity from other Components, as well as its {id ID} and data.
    # @return [Boolean] +true+
    def delete
      components.each do |component_manager, component_array|
        component_array.each do |component_id|
          component_manager[component_id].entities.delete(id)
          #self.remove FelFlame::Components.const_get(component_manager.name)[component_id]
        end
      end
      FelFlame::Entities.data[id] = nil
      @components = {}
      @id = nil
      true
    end

    # Add any number components to the Entity.
    # @param components_to_add [Component] Any number of components created from any component manager
    # @return [Boolean] +true+
    def add(*components_to_add)
      components_to_add.each do |component|
        if components[component.class].nil?
          components[component.class] = [component.id]
          component.entities.push id
          check_systems component, :addition_triggers
        elsif !components[component.class].include? component.id
          components[component.class].push component.id
          component.entities.push id
          check_systems component, :addition_triggers
        end
      end
      true
    end

    # triggers every system associated with this component's trigger
    # @return [Boolean] +true+
    # @!visibility private
    def check_systems(component, trigger_type)
      component_calls = component.class.send(trigger_type)
      component.send(trigger_type).each do |system|
        component_calls |= [system]
      end
      component_calls.sort_by(&:priority).reverse.each(&:call)
      true
    end

    # Remove a component from the Entity
    # @param components_to_remove [Component] A component created from any component manager
    # @return [Boolean] +true+
    def remove(*components_to_remove)
      components_to_remove.each do |component|
        check_systems component, :removal_triggers if component.entities.include? id
        component.entities.delete id
        components[component.class].delete component.id
      end
      true
    end

    # Export all data into a JSON String which can then be saved into a file
    # TODO: This function is not yet complete
    # @return [String] A JSON formatted String
    #def to_json() end

    class <<self
      include Enumerable
      # @return [Array<Entity>] Array of all Entities that exist
      # @!visibility private
      def data
        @data ||= []
      end

      # Gets an Entity from the given {id unique ID}. Usage is simular to how an Array lookup works
      #
      # @example
      #   # This gets the Entity with ID 7
      #   FelFlame::Entities[7]
      # @param entity_id [Integer]
      # @return [Entity] returns the Entity that uses the given unique ID, nil if there is no Entity associated with the given ID
      def [](entity_id)
        data[entity_id]
      end

      # Iterates over all entities. The data is compacted so that means index does not correlate to ID.
      # You also call other enumerable methods instead of each, such as +each_with_index+ or +select+
      # @return [Enumerator]
      def each(&block)
        data.compact.each(&block)
      end

      # Creates a new entity using the data from a JSON string
      # TODO: This function is not yet complete
      # @param json_string [String] A string that was exported originally using the {FelFlame::Entities#to_json to_json} function
      # @param opts [Keywords] What values(its {FelFlame::Entities#id ID} or the {FelFlame::ComponentManager#id component IDs}) should be overwritten TODO: this might change
      #def from_json(json_string, **opts) end
    end
  end
end