Skip to content

Commit

Permalink
Add prefab manual
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Jun 27, 2024
1 parent bdcdd00 commit 66cf3c3
Show file tree
Hide file tree
Showing 2 changed files with 855 additions and 212 deletions.
212 changes: 0 additions & 212 deletions docs/Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -985,218 +985,6 @@ ecs_set_scope(world, prev_scope);
ECS_SYSTEM(world, MoveNotInScope, EcsOnUpdate, transform.Position);
```

## Inheritance
Inheritance is the ability to share components between entities by _inheriting_ from them, by using the `IsA` relationship. This is a simple example in the C API:

```c
// Create a base entity
ecs_entity_t base = ecs_new(world);
ecs_set(world, base, Position, {10, 20});

// Derive from base
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base);

// e now shares Position with base
ecs_get(world, base, Position) == ecs_get(world, e, Position); // 1
```
`IsA` relationships can be added and removed dynamically, similar to how components can be added and removed:
```c
ecs_add_id(world, e, (IsA, base));
ecs_remove_id(world, e, (IsA, base));
```

`IsA` relationships can also be created through the `ECS_ENTITY` macro:

```c
ECS_ENTITY(world, base, Position);
ECS_ENTITY(world, e, (IsA, base));
```
`IsA` relationships can be nested:
```c
ecs_entity_t base = ecs_new(world);
ecs_set(world, base, Position, {10, 20});
ecs_entity_t derived = ecs_new_w_pair(world, EcsIsA, base);
// Derive from "derived" which is itself derived from base
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, derived);
// All three entities now share Position
ecs_get(world, base, Position) == ecs_get(world, e, Position); // 1
ecs_get(world, base, Position) == ecs_get(world, derived, Position); // 1
```

### Overriding
Derived entities can override components from their base by adding the component as they would normally. When overriding a component, the value of the base component is copied to the entity. This example shows how a derived entity overrides the Position component:

```c
// Shortcut for creating a base entity and setting Position
ecs_entity_t base = ecs_insert(world, ecs_value(Position, {10, 20}));

// Derive from the base
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, base);

// Override Position
ecs_add(world, e, Position);

// Position component no longer matches with base
ecs_get(world, base, Position) != ecs_get(world, e, Position); // 1

// Prints {10, 20}
const Position *p = ecs_get(world, e, Position);
printf("{%f, %f}\n", p->x, p->y);
```
When an entity shared a component from a base entity, we say that the component is "shared". If the component is not shared, it is "owned". After an entity overrides a component, it will own the component.
It is possible to remove an override, in which case the component will be shared with the base entity again:
```c
// Removes override on Position
ecs_remove(world, e, Position);
// Position is again shared with base
ecs_get(world, base, Position) == ecs_get(world, e, Position); // 1
```

Overrides work with nested `IsA` relationships:

```c
// Shortcut for creating a base entity and setting Position
ecs_entity_t base = ecs_new(world);
ecs_set(world, base, Position, {10, 20});
ecs_set(world, base, Velocity, {1, 1});

// Create derived entity, override Position
ecs_entity_t derived = ecs_new_w_pair(world, EcsIsA, base);
ecs_add(world, base, Position);

// Derive from 'derived', which is derived from base
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, derived);

// The entity now shares Position from derived, and Velocity from base
```
### Automatic overriding
In some scenarios it is desirable that an entity is initialized with a specific set of values, yet does not share the components from the base entity. In this case the derived entity can override each component individually, but this can become hard to maintain as components are added or removed to the base. This can be achieved by marking components as owned. Consider the following example:
```c
// Create a base. Simply deriving the base will share the component, but not override it.
ecs_entity_t Base = ecs_insert(world, ecs_value(Position, {10, 20}));
// Mark as OVERRIDE. This ensures that when base is derived from, Position is overridden
ecs_add_id(world, world, Base, ECS_AUTO_OVERRIDE | ecs_id(Position));
// Create entity from BaseType. This adds the IsA relationship in addition
// to overriding Position, effectively initializing the Position component for the entity.
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Base);
```

The combination of instancing, overriding and OVERRIDE is one of the fastest and easiest ways to create an entity with a set of initialized components. The OVERRIDE relationship can also be specified inside type expressions. The following example is equivalent to the previous one:

```c
ECS_ENTITY(world, Base, Position, auto_override | Position);

ecs_set(world, Base, Position, {10, 20});

ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, Base);
```
### Inheritance hierarchies
If a base entity has children, derived entities of that base entity will, when the `IsA` relationship is added, acquire the same set of children. Take this example:
```c
ecs_entity_t parent = ecs_new(world);
ecs_entity_t child_1 = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_entity_t child_2 = ecs_new_w_pair(world, EcsChildOf, parent);
// Derive from parent, two children are added to the entity
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, parent);
```

The children that are copied to the entity will have exactly the same set of components as the children of the base. For example, if the base child has components `Position, Velocity`, the derived child will also have `Position, Velocity`. Furthermore, the values of the base child components will be copied to the entity child:

```c
ecs_entity_t parent = ecs_new(world);
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_set_name(world, child, "Child"); // Give child a name, so we can look it up
ecs_set(world, child, Position, {10, 20});

// Derive from parent, two children are added to the derived entity
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, parent);
ecs_entity_t e_child = ecs_lookup_path(world, e, "Child");
const Position *p = ecs_get(world, e_child, Position);
printf("{%f, %f}\n", p->x, p->y); // Prints {10, 20}

// The components are not shared with the derived child!
ecs_get(world, child, Position) != ecs_get(world, e_child, Position); // 1
```
Since the children of the derived entity have the exact same components as the base children, their components are not shared. Component sharing between children is possible however, as `IsA` relationships are also copied over to the child of the derived entity:
```c
ecs_entity_t parent = ecs_new(world);
// Create child base from which we will share components
ecs_entity_t child_base = ecs_new(world);
ecs_set(world, child_base, Position, {10, 20});
ecs_set_name(world, child, "Child");
// Create actual child that inherits from the child base
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_add_pair(world, child, EcsIsA, child_base);
// Inherit from parent, two children are added to the entity
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, parent);
ecs_entity_t e_child = ecs_lookup_path(world, e, "Child");
// The component is now shared with the child and child_base
ecs_get(world, child, Position) == ecs_get(world, e_child, Position); // 1
```

### Prefabs
Prefabs are entities that can be used as templates for other entities. Prefabs are regular entities, except that they are not matched by default with systems. To create a prefab, add the `EcsPrefab` tag when creating an entity:

```c
ecs_entity_t prefab = ecs_new_w_id(world, EcsPrefab);
```

The `EcsPrefab` tag can also be added or removed dynamically:

```c
ecs_add_id(world, prefab, EcsPrefab);
ecs_remove_id(world, prefab, EcsPrefab);
```
Prefabs can also be created with the `ECS_PREFAB` macro:
```c
ECS_PREFAB(world, prefab, Position, Velocity);
```

To instantiate a prefab, an application can use the `IsA` relationship:

```c
ecs_entity_t e = ecs_new_w_pair(world, IsA, prefab);
```

To ensure that entities that inherit from a prefab don't also inherit the `Prefab` tag (which would cause them to not get matched with systems), the `Prefab` tag does not propagate to derived entities. This is illustrated in the following example:

```c
ECS_PREFAB(world, prefab, Position);

ecs_has(world, prefab, EcsPrefab); // true
ecs_has(world, prefab, Position); // true

ecs_entity_t e = ecs_new_w_pair(world, IsA, prefab);
ecs_has(world, e, EcsPrefab); // false
ecs_has(world, e, Position); // true
```
## Deferred operations
Applications can defer entity with the `ecs_defer_begin` and `ecs_defer_end` functions. This records all operations that happen inside the begin - end block, and executes them when `ecs_defer_end` is called. Deferred operations are useful when an application wants to make modifications to an entity while iterating, as doing this without deferring an operation could modify the underlying data structure. An example:

Expand Down
Loading

0 comments on commit 66cf3c3

Please sign in to comment.