View Source ECSx.Aspect behaviour (ECSx v0.1.0)
Aspects provide an API for working with Components of a specific type.
For example, if Entities in your application should have a "color" value, you will
create an Aspect called Color
. This allows you to add a color Component to an Entity
with add_component/1
, query the color value for a given Entity with get_component/1
or get_value/2
, query all Entities which have a color value with get_all/0
, remove
the color value from an Entity altogether with remove_component/1
, or test whether
an entity has a color with has_component?/1
.
usage
Usage
Each Aspect should have its own module, which defines a schema for the data, and optional ETS table settings. The schema defines the field names which will be used to reference each value.
defmodule MyApp.Aspects.Color do
use ECSx.Aspect,
schema: {:entity_id, :hue, :saturation, :lightness}
end
options
Options
:schema
- a tuple of field names:table_type
- ETS table type. Possible options are:set
,:ordered_set
,:bag
, and:duplicate_bag
. Defaults to:set
. See below for more information.:read_concurrency
- whentrue
, enables read concurrency for the ETS table. Defaults tofalse
table_type-option
:table_type
option
By default, ECSx creates ETS tables of type :set
for your Components. This means that
each Entity may have at most one Component of each Aspect. For example, if your application
has a "Height" Aspect, Entities would never need more than one Component to model that value.
However, if you had an Aspect such as "TakingDamageOverTime", you might want an Entity to
store each source of damage as a separate value, using multiple Components of the same Aspect.
To do this, set :table_type
to :bag
.
example
Example
defmodule TakingDamageOverTime do
use ECSx.Aspect,
schema: {:entity_id, :damage_per_second, :damage_type, :source_id},
table_type: :bag
end
alias TakingDamageOverTime, as: DOT
DOT.add_component(entity_id: hero.id, damage_per_second: 10, type: :poison, source_id: spider.id)
DOT.add_component(entity_id: hero.id, damage_per_second: 25, type: :fire, source_id: dragon.id)
DOT.get_component(hero.id)
[%{entity_id: ...}, %{...}]
DOT.get_value(hero.id, :damage_per_second)
[10, 25]
get_component-1-and-get_value-2
get_component/1
and get_value/2
The standard way to fetch the component(s) from an Entity is using
MyAspect.get_component(entity_id)
. If your table_type
is :set
or :ordered_set
,
this function will return a single Component, or nil
if the Entity does not have
that Aspect. If the table_type
is :bag
or :duplicate_bag
, then it will return
a list containing zero or more Components.
Each Component is represented by a map, using the keys provided by the schema. If you only
want a single value from the Component, use get_value/2
, passing the field name of the
desired value as the second argument.
examples
Examples
Color.get_component(entity_id)
%{entity_id: entity_id, hue: 300, saturation: 50, lightness: 45}
Color.get_value(entity_id, :hue)
300
Link to this section Summary
Callbacks
Creates a new component.
Gets all existing components of this aspect.
Gets an existing component from the table, given its entity ID.
Gets a single value from a component.
Checks if an entity has one or more components with this aspect.
Initializes the ETS table to store all components of this aspect.
Removes any existing components of this aspect from an entity.
Link to this section Types
Link to this section Callbacks
@callback add_component(attrs :: Keyword.t()) :: :ok
Creates a new component.
example
Example
ArmorRating.add_component(entity_id: 123, value: 10)
@callback get_all() :: [t()]
Gets all existing components of this aspect.
Gets an existing component from the table, given its entity ID.
Gets a single value from a component.
Checks if an entity has one or more components with this aspect.
@callback init() :: :ok
Initializes the ETS table to store all components of this aspect.
@callback remove_component(entity_id :: any()) :: :ok
Removes any existing components of this aspect from an entity.