View Source ECSx.Aspect behaviour (ECSx v0.1.1)

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 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 - when true, enables read concurrency for the ETS table. Defaults to false

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.

Link to this callback

get_component(entity_id)

View Source
@callback get_component(entity_id :: any()) :: t()

Gets an existing component from the table, given its entity ID.

Link to this callback

get_value(entity_id, field)

View Source
@callback get_value(entity_id :: any(), field :: atom()) :: value()

Gets a single value from a component.

Link to this callback

has_component?(entity_id)

View Source
@callback has_component?(entity_id :: any()) :: boolean()

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.

Link to this callback

remove_component(entity_id)

View Source
@callback remove_component(entity_id :: any()) :: :ok

Removes any existing components of this aspect from an entity.