Skip to content

Commit 2779efa

Browse files
committed
Improve the components manual
1 parent fb56158 commit 2779efa

1 file changed

Lines changed: 37 additions & 5 deletions

File tree

documentation/Components.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,31 @@ Stagehand introduces facilities and patterns to streamline working with componen
44

55
## Defining and Registering Components
66

7-
Through macros, boilerplate-free component definition and registration of components is possible. The macros also handle the per-component setup of [automatic change detection](ChangeDetection.md) behind the scenes.
8-
7+
Through macros, boilerplate-free component definition and registration of components is possible. The macros also handle the per-component setup of [automatic change detection](ChangeDetection.md) behind the scenes. Appending an underscore to a macro name (e.g., `FLOAT_` instead of `FLOAT`) opts out of change detection for that component.
98

109
### Manually defined & registered components
1110

11+
When none of the macro categories below fit your needs — for example, when defining a component that inherits from an arbitrary base class or requires custom Flecs hooks — you can register components manually using the `REGISTER` macro together with the Flecs and Stagehand APIs directly.
12+
13+
```cpp
14+
// 1. Define your struct.
15+
struct Velocity {
16+
float x = 0.0f;
17+
float y = 0.0f;
18+
float z = 0.0f;
19+
};
20+
21+
// 2. Register it. stagehand::register_component<T>() enables GDScript get/set access.
22+
REGISTER([](flecs::world& world) {
23+
world.component<Velocity>()
24+
.member<float>("x")
25+
.member<float>("y")
26+
.member<float>("z");
27+
stagehand::register_component<Velocity>("Velocity");
28+
});
29+
```
30+
31+
Change detection is not set up automatically with manual registration. To add it, declare a tag struct and call `stagehand::internal::register_change_detection_for_component<T, ChangeTag>(world)` inside your `REGISTER` block.
1232
1333
### Primitive C++ Types
1434
@@ -75,12 +95,16 @@ UINT64(AVeryHighInteger, 53925713520814); // Initialised with a default value.
7595
### Other C++ Types
7696

7797
#### `TAG(Name)` / `TAG_(Name)`
98+
99+
Empty marker component for entity classification and filtering. Tags carry no data; change detection does not apply to them.
78100
```cpp
79101
TAG(IsPlayer); // Defines a tag component.
80-
TAG_(IsGrounded); // Alias for TAG, no change detection applicable for tags.
102+
TAG_(IsGrounded); // Alias for TAG; change detection is not applicable to tags.
81103
```
82104

83105
#### `ENUM(Name, [UnderlyingType])` / `ENUM_(Name, [UnderlyingType])`
106+
107+
Registers an existing C++ `enum class` as an ECS component. The optional `UnderlyingType` tells Stagehand which integer type to use for GDScript serialisation; it should match the enum's declared underlying type (defaults to `uint8_t`).
84108
```cpp
85109
enum class AIState { Idle, Patrol, Chase };
86110
ENUM(AIState); // Defaults to uint8_t underlying type.
@@ -93,24 +117,32 @@ ENUM_(Weather); // Opt out of change detection.
93117
```
94118
95119
#### `POINTER(Name, Type, [DefaultValue])` / `POINTER_(Name, Type, [DefaultValue])`
120+
121+
Component wrapping a raw `Type*` pointer to an external object. Default-initialises to `nullptr` unless a value is provided.
96122
```cpp
97123
POINTER(CurrentTarget, Targetable); // Default-initialised to nullptr.
98124
POINTER(GameWindow, void, nullptr); // Initialised with an explicit default value.
99125
```
100126

101127
#### `VECTOR(Name, ElementType, [Initialiser])` / `VECTOR_(Name, ElementType, [Initialiser])`
128+
129+
Dynamic-size array component backed by `std::vector<ElementType>`.
102130
```cpp
103131
VECTOR(PathNodes, godot::Vector3); // Default-initialised to an empty vector.
104132
VECTOR(ItemIDs, int, {10, 23, 42}); // Initialised with a default list.
105133
```
106134
107-
#### `ARRAY(Name, ElementType, Size, [Initialiser])` / `ARRAY_(Name, ElementType, Size, [Initialiser])`
135+
#### `ARRAY(Name, ElementType, Count, [Initialiser])` / `ARRAY_(Name, ElementType, Count, [Initialiser])`
136+
137+
Fixed-size array component backed by `std::array<ElementType, Count>`. `Count` must be a compile-time constant.
108138
```cpp
109139
ARRAY(InputBuffer, uint8_t, 8); // An array of 8 elements that are default-initialised.
110140
ARRAY(ModelView, float, 4, {1,0,0,1}); // Initialised with a default list.
111141
```
112142

113143
#### `STRUCT(Name, { ... })` / `STRUCT_(Name, { ... })`
144+
145+
Multi-field aggregate struct component with automatic member reflection via Boost.PFR. All fields are individually registered with Flecs and exposed to GDScript as a `Dictionary`. The struct must be an aggregate type: no user-declared constructors, no virtual functions, and no private or protected non-static data members. All field types must be individually convertible to `godot::Variant`.
114146
```cpp
115147
STRUCT(PlayerStats, { float age; int rank; }); // Members are default-initialised.
116148
STRUCT(ColoredPoint, { godot::Vector3 position = godot::Vector3(0, 0, 0); godot::Color color = godot::Color(1, 1, 1); }); // Members initialised with default values.
@@ -121,7 +153,7 @@ STRUCT_(TrackedPosition, { float x = 0.0f; float y = 0.0f; float z = 0.0f; }); /
121153
122154
#### `GODOT_VARIANT(Name, Type, [DefaultValue])` / `GODOT_VARIANT_(Name, Type, [DefaultValue])`
123155
124-
These macros wrap Godot's built-in Variant types as components. They support both struct-based (Plain Old Data) types and class-based (handle) types.
156+
These macros wrap Godot's built-in Variant types as components. They support both struct-based (Plain Old Data) types and class-based (handle) types. `GODOT_VARIANT` includes change detection; `GODOT_VARIANT_` opts out of it.
125157
126158
#### Struct-based (Plain Old Data) Variants
127159
```cpp

0 commit comments

Comments
 (0)