View Source Ecspanse.Command (ECSpanse v0.10.0)

The Ecspanse.Command module provides a set of functions for managing entities, components and resources in the Ecspanse engine.

Commands are the only way to change the state of components and resources in Ecspanse. These commands can only be run from systems, otherwise an error will be thrown. The Ecspanse.Command module includes functions for managing relationships between entities, such as adding and removing children and parents. All entity and component related commands can run for batches (lists) for performance reasons.

All commands raise an error if the command fails.

Entity Relationships

The Ecspanse.Command module provides functions for managing relationships between entities. This is aslo a powerful tool to manage different kind of collections.

Ecspanse entities relationships are bidirectional associations

When adding or removing children or parents, they are automatically added or removed from the corresponding parent or children entities. The same applies when despawning entities.

Summary

Entities

Clones the specified entity and returns a new entity with the same components.

Clones the specified entity and all of its descendants and returns the newly cloned entity.

The same as despawn_entity!/1 but despawns multiple entities at once. It takes a list of entities as argument and returns :ok. See despawn_entity!/1 for more details.

The same as despawn_entity_and_descendants!/1 but despawns multiple entities and their descendants at once. It takes a list of entities as argument and returns :ok.

Despawns the specified entity and removes all of its components. It also removes the despawned entity from its parent and child entities, if any.

The same as despawn_entity!/1 but recursively despawns also all descendant tree of the entity.

The same as spawn_entity!/1 but spawns multiple entities at once. It takes a list of entity specs as argument and returns a list of Ecspanse.Entity structs.

Spawns a new entity with the given components and relations provided by the Ecspanse.Entity.entity_spec() type. When creating a new entity, at least one of the components:, children: or parents: must be provided in the entity spec, otherwise the entity cannot be persisted.

Relationships

Adds an entity as child to a parent entity.

The same as add_child!/2 but can perform multiple operations at once. For example, adding multiple children to multiple parents.

Adds a parent entity to a child entity.

The same as add_parent!/2 but can perform multiple operations at once. For example, adding multiple parents to multiple children.

Removes a child entity from a parent entity.

The same as remove_child!/2 but can perform multiple operations at once. For example, removing multiple children from multiple parents.

Removes a parent entity from a child entity.

The same as remove_parent!/2 but can perform multiple operations at once. For example, removing multiple parents from multiple children.

Components

The same as add_component!/2 but fetches the component after adding it.

Adds a new component to the specified entity.

The same as add_component!/2 but adds multiple components to multiple entities at once.

Removes an existing component from its entity. The components is destroyed.

The same as remove_component!/1 but removes multiple components at once.

The same as update_component!/2 but fetches the component after updating it.

Updates the state of an existing component.

The same as update_component!/2 but updates multiple components at once.

Resources

Deletes an existing global resource.

Inserts a new global resource.

Updates an existing global resource.

Entities

Link to this function

clone_entity!(entity, opts \\ [])

View Source
@spec clone_entity!(Ecspanse.Entity.t(), opts :: keyword()) :: Ecspanse.Entity.t()

Clones the specified entity and returns a new entity with the same components.

Due to the potentially large number of components that may be affected by this operation, it is recommended to run this function in a synchronous system (such as a frame_start or frame_end system) to avoid the need to lock all involved components.

Note

The entity's Ecspanse.Component.Children and Ecspanse.Component.Parents components are not cloned. Use deep_clone_entity!/2 to clone the entity and all of its descendants.

Options

  • :id - a custom unique ID for the entity (binary). If not provided, a random UUID will be generated.

Entity ID

The entity IDs must be unique. Attention when providing the :id option. If the provided ID is not unique, cloning the entity will raise an error.

Examples

  %Ecspanse.Entity{} = entity = Ecspanse.Command.clone_entity!(compass_entity)
Link to this function

deep_clone_entity!(entity, opts \\ [])

View Source
@spec deep_clone_entity!(Ecspanse.Entity.t(), [{:opts, keyword()}]) ::
  Ecspanse.Entity.t()

Clones the specified entity and all of its descendants and returns the newly cloned entity.

Due to the potentially large number of components that may be affected by this operation, it is recommended to run this function in a synchronous system (such as a frame_start or frame_end system) to avoid the need to lock all involved components.

Options

  • :id - a custom unique ID for the entity (binary). If not provided, a random UUID will be generated.

Entity ID

The entity IDs must be unique. Attention when providing the :id option. If the provided ID is not unique, cloning the entity will raise an error.

The cloned descendants entities will receive a random UUID as ID by default.

Cloning descendants

The deep cloning operates only for the descendants of the entity. If any of the descendants has a parent that is not a descendant of the entity, the parent will not be cloned or referenced.

If this is a desired behaviour, the parents should be added manually after the deep cloning.

Examples

  %Ecspanse.Entity{} = entity = Ecspanse.Command.deep_clone_entity!(enemy_entity)
@spec despawn_entities!([Ecspanse.Entity.t()]) :: :ok

The same as despawn_entity!/1 but despawns multiple entities at once. It takes a list of entities as argument and returns :ok. See despawn_entity!/1 for more details.

Link to this function

despawn_entities_and_descendants!(entities_list)

View Source
@spec despawn_entities_and_descendants!([Ecspanse.Entity.t()]) :: :ok

The same as despawn_entity_and_descendants!/1 but despawns multiple entities and their descendants at once. It takes a list of entities as argument and returns :ok.

@spec despawn_entity!(Ecspanse.Entity.t()) :: :ok

Despawns the specified entity and removes all of its components. It also removes the despawned entity from its parent and child entities, if any.

Due to the potentially large number of components that may be affected by this operation, it is recommended to run this function in a synchronous system (such as a frame_start or frame_end system) to avoid the need to lock all involved components.

Examples

  :ok = Ecspanse.Command.despawn_entity!(hero_entity)
Link to this function

despawn_entity_and_descendants!(entity)

View Source
@spec despawn_entity_and_descendants!(Ecspanse.Entity.t()) :: :ok

The same as despawn_entity!/1 but recursively despawns also all descendant tree of the entity.

This means that it will despawn the children of the entity, and their children, and so on.

It is an efficient way to remove an entire entity tree with just one operation. Extra attention required for entities with shared children.

See despawn_entity!/1 for more details.

@spec spawn_entities!([Ecspanse.Entity.entity_spec()]) :: [Ecspanse.Entity.t()]

The same as spawn_entity!/1 but spawns multiple entities at once. It takes a list of entity specs as argument and returns a list of Ecspanse.Entity structs.

See spawn_entity!/1 for more details.

@spec spawn_entity!(Ecspanse.Entity.entity_spec()) :: Ecspanse.Entity.t()

Spawns a new entity with the given components and relations provided by the Ecspanse.Entity.entity_spec() type. When creating a new entity, at least one of the components:, children: or parents: must be provided in the entity spec, otherwise the entity cannot be persisted.

Due to the potentially large number of components that may be affected by this operation, it is recommended to run this function in a synchronous system (such as a frame_start or frame_end system) to avoid the need to lock all involved components.

Examples

    %Ecspanse.Entity{} = Ecspanse.Command.spawn_entity!(
      {
        Ecspanse.Entity,
        id: "my_custom_id",
        components: [Demo.Components.Hero, {Demo.Components.Position, [x: 5, y: 3], [:hero, :map]}],
        children: [potion_entity, sword_entity],
        parents: [map_entity]
      }
    )

Relationships

Link to this function

add_child!(entity, child)

View Source
@spec add_child!(Ecspanse.Entity.t(), child :: Ecspanse.Entity.t()) :: :ok

Adds an entity as child to a parent entity.

Examples

  :ok = Ecspanse.Command.add_child!(hero_entity, sword_entity)
@spec add_children!([{Ecspanse.Entity.t(), children :: [Ecspanse.Entity.t()]}]) :: :ok

The same as add_child!/2 but can perform multiple operations at once. For example, adding multiple children to multiple parents.

It takes a list of two element tuples as argument, where the first element of the tuple is the parent entity and the second element is a list of children entities.

Examples

  :ok = Ecspanse.Command.add_children!([
    {hero_entity, [sword_entity]},
    {market_entity, [map_entity, potion_entity]}
  ])
Link to this function

add_parent!(entity, parent)

View Source
@spec add_parent!(Ecspanse.Entity.t(), parent :: Ecspanse.Entity.t()) :: :ok

Adds a parent entity to a child entity.

Examples

  :ok = Ecspanse.Command.add_parent!(sword_entity, hero_entity)
@spec add_parents!([{Ecspanse.Entity.t(), parents :: [Ecspanse.Entity.t()]}]) :: :ok

The same as add_parent!/2 but can perform multiple operations at once. For example, adding multiple parents to multiple children.

It takes a list of two element tuples as argument, where the first element of the tuple is the child entity and the second element is a list of parent entities.

Examples

  :ok = Ecspanse.Command.add_parents!([
    {sword_entity, [hero_entity]},
    {map_entity, [market_entity, vendor_entity]}
  ])
Link to this function

remove_child!(entity, child)

View Source
@spec remove_child!(Ecspanse.Entity.t(), child :: Ecspanse.Entity.t()) :: :ok

Removes a child entity from a parent entity.

Examples

  :ok = Ecspanse.Command.remove_child!(hero_entity, sword_entity)
@spec remove_children!([{Ecspanse.Entity.t(), children :: [Ecspanse.Entity.t()]}]) ::
  :ok

The same as remove_child!/2 but can perform multiple operations at once. For example, removing multiple children from multiple parents.

It takes a list of two element tuples as argument, where the first element of the tuple is the parent entity and the second element is a list of children entities.

Examples

  :ok = Ecspanse.Command.remove_children!([
    {hero_entity, [sword_entity]},
    {market_entity, [map_entity, potion_entity]}
  ])
Link to this function

remove_parent!(entity, parent)

View Source
@spec remove_parent!(Ecspanse.Entity.t(), parent :: Ecspanse.Entity.t()) :: :ok

Removes a parent entity from a child entity.

Examples

  :ok = Ecspanse.Command.remove_parent!(sword_entity, hero_entity)
@spec remove_parents!([{Ecspanse.Entity.t(), parents :: [Ecspanse.Entity.t()]}]) ::
  :ok

The same as remove_parent!/2 but can perform multiple operations at once. For example, removing multiple parents from multiple children.

It takes a list of two element tuples as argument, where the first element of the tuple is the child entity and the second element is a list of parent entities.

Examples

  :ok = Ecspanse.Command.remove_parents!([
    {sword_entity, [hero_entity]},
    {map_entity, [market_entity, vendor_entity]}
  ])

Components

Link to this function

add_and_fetch_component!(entity, component_spec)

View Source
@spec add_and_fetch_component!(
  Ecspanse.Entity.t(),
  Ecspanse.Component.component_spec()
) ::
  {:ok, component_state :: struct()}

The same as add_component!/2 but fetches the component after adding it.

Link to this function

add_component!(entity, component_spec)

View Source
@spec add_component!(Ecspanse.Entity.t(), Ecspanse.Component.component_spec()) :: :ok

Adds a new component to the specified entity.

Info

An entity cannot have multiple components of the same type. If an attempt is made to insert a component that already exists for the entity, an error will be raised.

Examples

  :ok = Ecspanse.Command.add_component!(hero_entity, Demo.Components.Gold)
  :ok = Ecspanse.Command.add_component!(hero_entity, {Demo.Components.Gold, [amount: 5], [:resource, :available]})
@spec add_components!([{Ecspanse.Entity.t(), [Ecspanse.Component.component_spec()]}]) ::
  :ok

The same as add_component!/2 but adds multiple components to multiple entities at once.

It takes a list of two element tuples as argument, where the first element of the tuple is the entity and the second element is a list of component specs.

Examples

  :ok = Ecspanse.Command.add_components!([
    {inventory_item_entity, [Demo.Components.Sword]},
    {hero_entity, [Demo.Components.Position, Demo.Components.Hero]}
  ])
Link to this function

remove_component!(component)

View Source
@spec remove_component!(component :: struct()) :: :ok

Removes an existing component from its entity. The components is destroyed.

Examples

  :ok = Ecspanse.Command.remove_component!(invisibility_component)
Link to this function

remove_components!(components)

View Source
@spec remove_components!([component :: struct()]) :: :ok

The same as remove_component!/1 but removes multiple components at once.

Link to this function

update_and_fetch_component!(component, changes_keyword)

View Source
@spec update_and_fetch_component!(
  current_component :: struct(),
  state_changes :: keyword()
) ::
  {:ok, component_state :: struct()}

The same as update_component!/2 but fetches the component after updating it.

Link to this function

update_component!(component, changes_keyword)

View Source
@spec update_component!(current_component :: struct(), state_changes :: keyword()) ::
  :ok

Updates the state of an existing component.

The function takes two arguments: the component struct to update and a keyword list of changes to apply.

Examples

  :ok = Ecspanse.Command.update_component!(position_component, x: :12)
Link to this function

update_components!(list)

View Source
@spec update_components!([{current_component :: struct(), state_changes :: keyword()}]) ::
  :ok

The same as update_component!/2 but updates multiple components at once.

It takes a list of two element tuples as argument, where the first element of the tuple is the component struct and the second element is a keyword list of changes to apply.

Examples

  :ok = Ecspanse.Command.update_components!([
    {position_component, x: 7, y: 9},
    {gold_component, amount: 12}
  ])

Resources

Link to this function

delete_resource!(resource)

View Source
@spec delete_resource!(resource :: struct()) :: deleted_resource :: struct()

Deletes an existing global resource.

Note

Resources can be created, updated or deleted only from synchronous systems.

Examples

  %Demo.Resources.Lobby{} = Ecspanse.Command.delete_resource!(lobby_resource)
Link to this function

insert_resource!(resource_spec)

View Source
@spec insert_resource!(resource_spec :: Ecspanse.Resource.resource_spec()) ::
  resource :: struct()

Inserts a new global resource.

Info

An Ecspanse instance can only hold one resource of each type at a time. If an attempt is made to insert a resource that already exists, an error will be raised.

Note

Resources can be created, updated or deleted only from synchronous systems.

Examples

  %Demo.Resources.Lobby{} = Ecspanse.Command.insert_resource!({Demo.Resources.Lobby, player_count: 0})
Link to this function

update_resource!(resource, state_changes)

View Source
@spec update_resource!(resource :: struct(), state_changes :: keyword()) ::
  updated_resource :: struct()

Updates an existing global resource.

Note

Resources can be created, updated or deleted only from synchronous systems.

Examples

  %Demo.Resources.Lobby{} = Ecspanse.Command.update_resource!(lobby_resource, player_count: 1)