Skip to content

Commit f0787c0

Browse files
committed
Add component inheritance examples
1 parent 91be346 commit f0787c0

18 files changed

Lines changed: 339 additions & 93 deletions

File tree

examples/c/queries/component_inheritance/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
],
88
"public": false
99
}
10-
}
10+
}
Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,74 @@
11
#include <component_inheritance.h>
22
#include <stdio.h>
33

4-
// This example shows how queries can be used to match simple inheritance trees.
4+
// This example shows how queries can match components that derive from a base
5+
// component through the IsA relationship. A query for the base component
6+
// matches all entities that have a derived component, and can read the members
7+
// that are inherited from the base. See the tag_inheritance example for
8+
// inheritance trees built from tags instead of components.
59

6-
int main(int argc, char *argv[]) {
7-
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
10+
// Buf is the base component. HealthBuf and ManaBuf derive from it, so they
11+
// start with the same members as Buf (the base layout is a prefix of the
12+
// derived layout).
13+
typedef struct {
14+
float value;
15+
} Buf;
16+
17+
typedef struct {
18+
float value;
19+
} HealthBuf;
820

9-
// Use convenience macros to create simple hierarchy of unit types.
10-
// This macro call:
11-
// ECS_ENTITY(ecs, CombatUnit, (IsA, Unit))
12-
//
13-
// is the same as these C statements:
14-
// ecs_entity_t CombatUnit = ecs_new_entity("CombatUnit");
15-
// ecs_add_pair(ecs, CombatUnit, EcsIsA, Unit);
21+
typedef struct {
22+
float value;
23+
} ManaBuf;
1624

17-
ECS_TAG(ecs, Unit);
18-
ECS_ENTITY(ecs, CombatUnit, (IsA, Unit));
19-
ECS_ENTITY(ecs, MeleeUnit, (IsA, CombatUnit));
20-
ECS_ENTITY(ecs, RangedUnit, (IsA, CombatUnit));
25+
int main(int argc, char *argv[]) {
26+
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
2127

22-
ECS_ENTITY(ecs, Warrior, (IsA, MeleeUnit));
23-
ECS_ENTITY(ecs, Wizard, (IsA, RangedUnit));
24-
ECS_ENTITY(ecs, Marksman, (IsA, RangedUnit));
25-
ECS_ENTITY(ecs, Builder, (IsA, Unit));
28+
ECS_COMPONENT(ecs, Buf);
29+
ECS_COMPONENT(ecs, HealthBuf);
30+
ECS_COMPONENT(ecs, ManaBuf);
2631

27-
// Create a few units
28-
ecs_entity_t warrior_1 = ecs_entity(ecs, { .name = "warrior_1" });
29-
ecs_add(ecs, warrior_1, Warrior);
30-
ecs_entity_t warrior_2 = ecs_entity(ecs, { .name = "warrior_2" });
31-
ecs_add(ecs, warrior_2, Warrior);
32+
// Make the ECS aware of the inheritance relationships.
33+
ecs_add_pair(ecs, ecs_id(HealthBuf), EcsIsA, ecs_id(Buf));
34+
ecs_add_pair(ecs, ecs_id(ManaBuf), EcsIsA, ecs_id(Buf));
3235

33-
ecs_entity_t marksman_1 = ecs_entity(ecs, { .name = "marksman_1" });
34-
ecs_add(ecs, marksman_1, Marksman);
35-
ecs_entity_t marksman_2 = ecs_entity(ecs, { .name = "marksman_2" });
36-
ecs_add(ecs, marksman_2, Marksman);
36+
// Create a few entities with derived buf components
37+
ecs_entity_t warrior = ecs_entity(ecs, { .name = "warrior" });
38+
ecs_set(ecs, warrior, HealthBuf, { .value = 10 });
3739

38-
ecs_entity_t wizard_1 = ecs_entity(ecs, { .name = "wizard_1" });
39-
ecs_add(ecs, wizard_1, Wizard);
40-
ecs_entity_t wizard_2 = ecs_entity(ecs, { .name = "wizard_2" });
41-
ecs_add(ecs, wizard_2, Wizard);
40+
ecs_entity_t wizard = ecs_entity(ecs, { .name = "wizard" });
41+
ecs_set(ecs, wizard, ManaBuf, { .value = 25 });
4242

43-
ecs_entity_t builder_1 = ecs_entity(ecs, { .name = "builder_1" });
44-
ecs_add(ecs, builder_1, Builder);
45-
ecs_entity_t builder_2 = ecs_entity(ecs, { .name = "builder_2" });
46-
ecs_add(ecs, builder_2, Builder);
43+
ecs_entity_t paladin = ecs_entity(ecs, { .name = "paladin" });
44+
ecs_set(ecs, paladin, HealthBuf, { .value = 5 });
4745

48-
// Create a query to find all ranged units
46+
// Create a query for the base component. This matches all entities with a
47+
// component that derives from Buf.
4948
ecs_query_t *q = ecs_query(ecs, {
50-
.terms = {{ .id = RangedUnit }}
49+
.terms = {{ .id = ecs_id(Buf) }}
5150
});
5251

53-
// Iterate the query
52+
// Iterate the query. Because the matched component can be a derived type
53+
// that is larger than Buf, use ecs_base_field to get the field pointer and
54+
// ecs_field_stride to advance from one element to the next.
5455
ecs_iter_t it = ecs_query_iter(ecs, q);
5556
while (ecs_query_next(&it)) {
57+
void *bufs = ecs_base_field(&it, Buf, 0);
58+
size_t stride = ecs_field_stride(&it, 0);
5659
for (int i = 0; i < it.count; i ++) {
57-
printf("Unit %s found\n", ecs_get_name(ecs, it.entities[i]));
60+
Buf *buf = ECS_OFFSET(bufs, stride * i);
61+
printf("%s has buf value %.0f\n",
62+
ecs_get_name(ecs, it.entities[i]), buf->value);
5863
}
5964
}
6065

6166
ecs_query_fini(q);
6267

6368
// Output
64-
// Unit wizard_1 found
65-
// Unit wizard_2 found
66-
// Unit marksman_1 found
67-
// Unit marksman_2 found
69+
// warrior has buf value 10
70+
// paladin has buf value 5
71+
// wizard has buf value 25
6872

6973
return ecs_fini(ecs);
7074
}

examples/c/queries/setting_variables/src/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <setting_variables.h>
22
#include <stdio.h>
33

4-
// This example extends the component_inheritance example, and shows how
4+
// This example extends the tag_inheritance example, and shows how
55
// we can use a single query to match units from different players and platoons
66
// by setting query variables before we iterate.
77
//
@@ -14,7 +14,7 @@ static const int PlatoonsPerPlayer = 3;
1414
int main(int argc, char *argv[]) {
1515
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
1616

17-
// Unit datamodel - see component_inheritance example
17+
// Unit datamodel - see tag_inheritance example
1818
ECS_TAG(ecs, Unit);
1919
ECS_ENTITY(ecs, CombatUnit, (IsA, Unit));
2020
ECS_ENTITY(ecs, MeleeUnit, (IsA, CombatUnit));
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cc_binary(
2+
name = "tag_inheritance",
3+
srcs = glob([
4+
"src/*.c",
5+
"include/**/*.h",
6+
]),
7+
includes = ["include"],
8+
deps = [
9+
"//:flecs",
10+
],
11+
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef TAG_INHERITANCE_H
2+
#define TAG_INHERITANCE_H
3+
4+
/* This generated file contains includes for project dependencies */
5+
#include "tag_inheritance/bake_config.h"
6+
7+
#ifdef __cplusplus
8+
extern "C" {
9+
#endif
10+
11+
#ifdef __cplusplus
12+
}
13+
#endif
14+
15+
#endif
16+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
)
3+
(.)
4+
.|.
5+
| |
6+
_.--| |--._
7+
.-'; ;`-'& ; `&.
8+
\ & ; & &_/
9+
|"""---...---"""|
10+
\ | | | | | | | /
11+
`---.|.|.|.---'
12+
13+
* This file is generated by bake.lang.c for your convenience. Headers of
14+
* dependencies will automatically show up in this file. Include bake_config.h
15+
* in your main project file. Do not edit! */
16+
17+
#ifndef TAG_INHERITANCE_BAKE_CONFIG_H
18+
#define TAG_INHERITANCE_BAKE_CONFIG_H
19+
20+
/* Headers of public dependencies */
21+
#include <flecs.h>
22+
23+
#endif
24+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"id": "tag_inheritance",
3+
"type": "application",
4+
"value": {
5+
"use": [
6+
"flecs"
7+
],
8+
"public": false
9+
}
10+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include <tag_inheritance.h>
2+
#include <stdio.h>
3+
4+
// This example shows how queries can be used to match simple inheritance trees
5+
// built from tags. See the component_inheritance example for inheritance trees
6+
// built from components with data.
7+
8+
int main(int argc, char *argv[]) {
9+
ecs_world_t *ecs = ecs_init_w_args(argc, argv);
10+
11+
// Use convenience macros to create simple hierarchy of unit types.
12+
// This macro call:
13+
// ECS_ENTITY(ecs, CombatUnit, (IsA, Unit))
14+
//
15+
// is the same as these C statements:
16+
// ecs_entity_t CombatUnit = ecs_new_entity("CombatUnit");
17+
// ecs_add_pair(ecs, CombatUnit, EcsIsA, Unit);
18+
19+
ECS_TAG(ecs, Unit);
20+
ECS_ENTITY(ecs, CombatUnit, (IsA, Unit));
21+
ECS_ENTITY(ecs, MeleeUnit, (IsA, CombatUnit));
22+
ECS_ENTITY(ecs, RangedUnit, (IsA, CombatUnit));
23+
24+
ECS_ENTITY(ecs, Warrior, (IsA, MeleeUnit));
25+
ECS_ENTITY(ecs, Wizard, (IsA, RangedUnit));
26+
ECS_ENTITY(ecs, Marksman, (IsA, RangedUnit));
27+
ECS_ENTITY(ecs, Builder, (IsA, Unit));
28+
29+
// Create a few units
30+
ecs_entity_t warrior_1 = ecs_entity(ecs, { .name = "warrior_1" });
31+
ecs_add(ecs, warrior_1, Warrior);
32+
ecs_entity_t warrior_2 = ecs_entity(ecs, { .name = "warrior_2" });
33+
ecs_add(ecs, warrior_2, Warrior);
34+
35+
ecs_entity_t marksman_1 = ecs_entity(ecs, { .name = "marksman_1" });
36+
ecs_add(ecs, marksman_1, Marksman);
37+
ecs_entity_t marksman_2 = ecs_entity(ecs, { .name = "marksman_2" });
38+
ecs_add(ecs, marksman_2, Marksman);
39+
40+
ecs_entity_t wizard_1 = ecs_entity(ecs, { .name = "wizard_1" });
41+
ecs_add(ecs, wizard_1, Wizard);
42+
ecs_entity_t wizard_2 = ecs_entity(ecs, { .name = "wizard_2" });
43+
ecs_add(ecs, wizard_2, Wizard);
44+
45+
ecs_entity_t builder_1 = ecs_entity(ecs, { .name = "builder_1" });
46+
ecs_add(ecs, builder_1, Builder);
47+
ecs_entity_t builder_2 = ecs_entity(ecs, { .name = "builder_2" });
48+
ecs_add(ecs, builder_2, Builder);
49+
50+
// Create a query to find all ranged units
51+
ecs_query_t *q = ecs_query(ecs, {
52+
.terms = {{ .id = RangedUnit }}
53+
});
54+
55+
// Iterate the query
56+
ecs_iter_t it = ecs_query_iter(ecs, q);
57+
while (ecs_query_next(&it)) {
58+
for (int i = 0; i < it.count; i ++) {
59+
printf("Unit %s found\n", ecs_get_name(ecs, it.entities[i]));
60+
}
61+
}
62+
63+
ecs_query_fini(q);
64+
65+
// Output
66+
// Unit wizard_1 found
67+
// Unit wizard_2 found
68+
// Unit marksman_1 found
69+
// Unit marksman_2 found
70+
71+
return ecs_fini(ecs);
72+
}

examples/c/queries/transitive_queries/src/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// San Francisco is located in the United States
1111
// Therefore Bob also lives in the United States.
1212
//
13-
// An example of transitivity can be seen in the component_inheritance example.
13+
// An example of transitivity can be seen in the tag_inheritance example.
1414
// This example uses the builtin IsA relationship, which is transitive. This
1515
// example shows how to achieve similar behavior with a user-defined relationship.
1616

examples/cpp/queries/component_inheritance/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
"language": "c++",
99
"public": false
1010
}
11-
}
11+
}

0 commit comments

Comments
 (0)