View Source ECSx.Aspect behaviour (ECSx v0.2.0)
Provides 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 query_one/1
,
query all Entities which have a color value with query_all/1
, 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)
query_one-1-and-query_all-1
query_one/1
and query_all/1
The standard way to fetch the Component(s) from an Entity is using a Query. Each aspect
provides two Query functions: query_one/1
and query_all/1
. The former returns a single
result, and will raise an ECSx.QueryError
if more than one result is found. The latter
will return a list with any number of results.
These Query functions have two possible parameters:
:match
- A keyword list of the fields and values for which to search. If a:match
is not given, the entire Aspect table will be returned.:value
- By default, each Component returned by a Query will be in the form of a map, using the keys provided by its Aspect schema. If you only care about one field from the Component, you can instead return unwrapped values withvalue: :field_name
examples
Examples
Color.query_one(match: [entity_id: entity_id])
%{entity_id: entity_id, hue: 300, saturation: 50, lightness: 45}
Color.query_one(match: [entity_id: entity_id], value: :hue)
300
Color.query_all()
[%{entity_id: entity_id, ...}, %{...}, ...]
Color.query_all(value: :entity_id)
[entity_id, another_entity_id, ...]
Link to this section Summary
Callbacks
Creates a new component.
Checks if an entity has one or more components with this aspect.
Query for all components of this aspect with optional match conditions.
Query for a single component of this aspect with optional match conditions.
Removes any existing components of this aspect from an entity.
Link to this section Types
@type t() :: module()
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)
Checks if an entity has one or more components with this aspect.
@callback query_all(query :: Keyword.t()) :: [ECSx.Component.t() | ECSx.Component.value()]
Query for all components of this aspect with optional match conditions.
Examples
# Get the ID of each entity with zero velocity in the x-y plane
Velocity.query_all(match: [vx: 0, vy: 0], value: :entity_id)
@callback query_one(query :: Keyword.t()) :: ECSx.Component.t() | ECSx.Component.value()
Query for a single component of this aspect with optional match conditions.
Raises if more than one component is returned.
Examples
# Get the Velocity component for entity 123
Velocity.query_one(match: [entity_id: 123])
@callback remove_component(entity_id :: any()) :: :ok
Removes any existing components of this aspect from an entity.