From 0fbb48c7b0ef7070664945ef22840b0bfbfe9153 Mon Sep 17 00:00:00 2001 From: realtradam Date: Fri, 9 Jul 2021 03:32:01 -0400 Subject: gem conversion --- lib/felflame.rb | 59 +++++++++ lib/felflame/component_manager.rb | 245 ++++++++++++++++++++++++++++++++++++++ lib/felflame/entity_manager.rb | 135 +++++++++++++++++++++ lib/felflame/scene_manager.rb | 58 +++++++++ lib/felflame/stage_manager.rb | 70 +++++++++++ lib/felflame/system_manager.rb | 213 +++++++++++++++++++++++++++++++++ lib/felflame/version.rb | 5 + 7 files changed, 785 insertions(+) create mode 100644 lib/felflame.rb create mode 100644 lib/felflame/component_manager.rb create mode 100644 lib/felflame/entity_manager.rb create mode 100644 lib/felflame/scene_manager.rb create mode 100644 lib/felflame/stage_manager.rb create mode 100644 lib/felflame/system_manager.rb create mode 100644 lib/felflame/version.rb (limited to 'lib') diff --git a/lib/felflame.rb b/lib/felflame.rb new file mode 100644 index 0000000..a7d6940 --- /dev/null +++ b/lib/felflame.rb @@ -0,0 +1,59 @@ +require_relative 'felflame/entity_manager' +require_relative 'felflame/component_manager' +require_relative 'felflame/system_manager' +require_relative 'felflame/scene_manager' +require_relative 'felflame/stage_manager' + +require_relative "felflame/version" + +# The FelFlame namespace where all its functionality resides under. +class FelFlame + class <] + def addition_triggers + @addition_triggers ||= [] + end + + # Stores references to systems that should be triggered when a + # component from this manager is removed. + # Do not edit this array as it is managed by FelFlame automatically. + # @return [Array] + def removal_triggers + @removal_triggers ||= [] + end + + # Stores references to systems that should be triggered when an + # attribute from this manager is changed. + # Do not edit this hash as it is managed by FelFlame automatically. + # @return [Hash>] + def attr_triggers + @attr_triggers ||= {} + end + + # Creates a new component and sets the values of the attributes given to it. If an attritbute is not passed then it will remain as the default. + # @param attrs [Keyword: Value] You can pass any number of Keyword-Value pairs + # @return [Component] + def initialize(**attrs) + # Prepare the object + # (this is a function created with metaprogramming + # in FelFlame::Components + set_defaults + + # Generate ID + new_id = self.class.data.find_index { |i| i.nil? } + new_id = self.class.data.size if new_id.nil? + @id = new_id + + # Fill params + attrs.each do |key, value| + send "#{key}=", value + end + + # Save Component + self.class.data[new_id] = self + end + + class <] + def addition_triggers + @addition_triggers ||= [] + end + + # Stores references to systems that should be triggered when this + # component is removed from an enitity. + # Do not edit this array as it is managed by FelFlame automatically. + # @return [Array] + def removal_triggers + @removal_triggers ||= [] + end + + # Stores references to systems that should be triggered when an + # attribute from this component changed. + # Do not edit this hash as it is managed by FelFlame automatically. + # @return [Hash] + def attr_triggers + @attr_triggers ||= {} + end + + # @return [Array] Array of all Components that belong to a given component manager + # @!visibility private + def data + @data ||= [] + end + + # Gets a Component from the given {id unique ID}. Usage is simular to how an Array lookup works. + # + # @example + # # this gets the 'Health' Component with ID 7 + # FelFlame::Components::Health[7] + # @param component_id [Integer] + # @return [Component] Returns the Component that uses the given unique {id ID}, nil if there is no Component associated with the given {id ID} + def [](component_id) + data[component_id] + end + + # Iterates over all components within the component manager. + # Special Enumerable methods like +map+ or +each_with_index+ are not implemented + # @return [Enumerator] + def each(&block) + data.compact.each(&block) + end + end + + # An alias for the {id ID Reader} + # @return [Integer] + def to_i + id + end + + # A list of entity ids that are linked to the component + # @return [Array] + def entities + @entities ||= [] + end + + # Update attribute values using a hash or keywords. + # @return [Hash] Hash of updated attributes + def update_attrs(**opts) + opts.each do |key, value| + send "#{key}=", value + end + end + + # Execute systems that have been added to execute on variable change + # @return [Boolean] +true+ + def attr_changed_trigger_systems(attr) + systems_to_execute = self.class.attr_triggers[attr] + systems_to_execute = [] if systems_to_execute.nil? + + systems_to_execute |= attr_triggers[attr] unless attr_triggers[attr].nil? + + systems_to_execute.sort_by(&:priority).reverse.each(&:call) + true + end + + # Removes this component from the list and purges all references to this Component from other Entities, as well as its {id ID} and data. + # @return [Boolean] +true+. + def delete + addition_triggers.each do |system| + system.clear_triggers component_or_manager: self + end + # This needs to be cloned because indices get deleted as + # the remove command is called, breaking the loop if it + # wasn't referencing a clone(will get Nil errors) + iter = entities.map(&:clone) + iter.each do |entity_id| + FelFlame::Entities[entity_id].remove self #unless FelFlame::Entities[entity_id].nil? + end + self.class.data[id] = nil + instance_variables.each do |var| + instance_variable_set(var, nil) + end + true + end + + # @return [Hash] A hash, where all the keys are attributes linked to their respective values. + def attrs + return_hash = instance_variables.each_with_object({}) do |key, final| + final[key.to_s.delete_prefix('@').to_sym] = instance_variable_get(key) + end + return_hash.delete(:attr_triggers) + return_hash + end + + # Export all data into a JSON String, which could then later be loaded or saved to a file + # TODO: This function is not yet complete + # @return [String] a JSON formatted String + #def to_json + # # should return a json or hash of all data in this component + #end + end +end diff --git a/lib/felflame/entity_manager.rb b/lib/felflame/entity_manager.rb new file mode 100644 index 0000000..74fc4c3 --- /dev/null +++ b/lib/felflame/entity_manager.rb @@ -0,0 +1,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>] + 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 <] 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 diff --git a/lib/felflame/scene_manager.rb b/lib/felflame/scene_manager.rb new file mode 100644 index 0000000..315dd55 --- /dev/null +++ b/lib/felflame/scene_manager.rb @@ -0,0 +1,58 @@ +class FelFlame + class Scenes + # The Constant name assigned to this Scene + attr_reader :const_name + + # Allows overwriting the storage of systems, such as for clearing. + # This method should generally only need to be used internally and + # not by a game developer/ + # @!visibility private + attr_writer :systems + + # Create a new Scene using the name given + # @param name [String] String format must follow requirements of a constant + def initialize(name) + FelFlame::Scenes.const_set(name, self) + @const_name = name + end + + # The list of Systems this Scene contains + # @return [Array] + def systems + @systems ||= [] + end + + # Execute all systems in this Scene, in the order of their priority + # @return [Boolean] +true+ + def call + systems.each(&:call) + true + end + + # Adds any number of Systems to this Scene + # @return [Boolean] +true+ + def add(*systems_to_add) + self.systems |= systems_to_add + systems.sort_by!(&:priority) + FelFlame::Stage.update_systems_list if FelFlame::Stage.scenes.include? self + true + end + + # Removes any number of SystemS from this Scene + # @return [Boolean] +true+ + def remove(*systems_to_remove) + self.systems -= systems_to_remove + systems.sort_by!(&:priority) + FelFlame::Stage.update_systems_list if FelFlame::Stage.scenes.include? self + true + end + + # Removes all Systems from this Scene + # @return [Boolean] +true+ + def clear + systems.clear + FelFlame::Stage.update_systems_list if FelFlame::Stage.scenes.include? self + true + end + end +end diff --git a/lib/felflame/stage_manager.rb b/lib/felflame/stage_manager.rb new file mode 100644 index 0000000..87ee955 --- /dev/null +++ b/lib/felflame/stage_manager.rb @@ -0,0 +1,70 @@ +class FelFlame + class Stage + class <] + def scenes + @scenes ||= [] + end + + # Stores systems in the order the stage manager needs to call them + # This method should generally only need to be used internally and not by a game developer + # @!visibility private + def systems + @systems ||= [] + end + end + end +end diff --git a/lib/felflame/system_manager.rb b/lib/felflame/system_manager.rb new file mode 100644 index 0000000..cab2c4d --- /dev/null +++ b/lib/felflame/system_manager.rb @@ -0,0 +1,213 @@ +class FelFlame + class Systems + # How early this System should be executed in a list of Systems + attr_accessor :priority + + # The Constant name assigned to this System + attr_reader :const_name + + # Allows overwriting the storage of triggers, such as for clearing. + # This method should generally only need to be used internally and + # not by a game developer. + # @!visibility private + attr_writer :addition_triggers, :removal_triggers, :attr_triggers + + def priority=(priority) + @priority = priority + FelFlame::Stage.systems.sort_by!(&:priority) + end + # Stores references to components or their managers that trigger + # this component when a component or component from that manager + # is added to an entity. + # Do not edit this hash as it is managed by FelFlame automatically. + # @return [Array] + def addition_triggers + @addition_triggers ||= [] + end + + # Stores references to components or their managers that trigger + # this component when a component or component from that manager + # is removed from an entity. + # Do not edit this hash as it is managed by FelFlame automatically. + # @return [Array] + def removal_triggers + @removal_triggers ||= [] + end + + + # Stores references to systems that should be triggered when an + # attribute from this manager is changed + # Do not edit this hash as it is managed by FelFlame automatically. + # @return [Hash>] + def attr_triggers + @attr_triggers ||= {} + end + + class <