-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathquery_setting_variables.rs
143 lines (118 loc) · 4.59 KB
/
query_setting_variables.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::z_ignore_test_common::*;
use flecs_ecs::prelude::*;
// This example extends the component_inheritance example, and shows how
// we can use a single query to match units from different players and platoons
// by setting query variables before we iterate.
//
// The units in this example belong to a platoon, with the platoons belonging
// to a player.
// unit datamodel
#[derive(Component)]
struct Unit;
#[derive(Component)]
struct CombatUnit;
#[derive(Component)]
struct MeleeUnit;
#[derive(Component)]
struct RangedUnit;
#[derive(Component)]
struct Warrior;
#[derive(Component)]
struct Wizard;
#[derive(Component)]
struct Marksman;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Platoon;
const PLAYER_COUNT: usize = 100;
const PLATOONS_PER_PLAYER: usize = 3;
fn main() {
let world = World::new();
// Make the ECS aware of the inheritance relationships. Note that IsA
// relationship used here is the same as in the prefab example.
world.component::<CombatUnit>().is_a::<Unit>();
world.component::<MeleeUnit>().is_a::<CombatUnit>();
world.component::<RangedUnit>().is_a::<CombatUnit>();
world.component::<Warrior>().is_a::<MeleeUnit>();
world.component::<Wizard>().is_a::<RangedUnit>();
world.component::<Marksman>().is_a::<RangedUnit>();
// Populate store with players and platoons
for p in 0..PLAYER_COUNT {
let player = if p == 0 {
// Give first player a name so we can look it up later
world.entity_named("MyPlayer")
} else {
world.entity()
};
// Add player tag so we can query for all players if we want to
player.add::<Player>();
for _ in 0..PLATOONS_PER_PLAYER {
let platoon = world
.entity()
.add_first::<Player>(player)
// Add platoon tag so we can query for all platoons if we want to
.add::<Platoon>();
// Add warriors, wizards and marksmen to the platoon
world
.entity()
.add::<Warrior>()
.add_first::<Platoon>(platoon);
world
.entity()
.add::<Marksman>()
.add_first::<Platoon>(platoon);
world.entity().add::<Wizard>().add_first::<Platoon>(platoon);
}
}
// Create a query to find all RangedUnits for a platoon/player. The
// equivalent query in the query DSL would look like this:
// (Platoon, $Platoon), Player($Platoon, $Player)
//
// The way to read how this query is evaluated is:
// - find all entities with (Platoon, *), store * in _Platoon
// - check if _Platoon has (Player, *), store * in _Player
let mut query = world
.query::<()>()
.with::<RangedUnit>()
.with::<&Platoon>()
.set_second_name("$platoon")
.with_first_name::<&Player>("$player")
.set_src_name("$platoon")
.build();
// If we would iterate this query it would return all ranged units for all
// platoons & for all players. We can limit the results to just a single
// platoon or a single player setting a variable beforehand. In this example
// we'll just find all platoons & ranged units for a single player.
let player_var = query.find_var("player").unwrap();
let platoon_var = query.find_var("platoon").unwrap();
// Iterate query, limit the results to units of MyPlayer
query
.set_var(player_var, world.lookup_recursive("MyPlayer"))
.each_iter(|it, index, _| {
let unit = it.entity(index);
println!(
"Unit id: {} of class {} in platoon id: {} for player {}",
unit,
it.id(0).to_str(),
it.get_var(platoon_var),
it.get_var(player_var)
);
});
// Output:
// Unit id: 529 of class Wizard in platoon id: 526 for player MyPlayer
// Unit id: 533 of class Wizard in platoon id: 530 for player MyPlayer
// Unit id: 537 of class Wizard in platoon id: 534 for player MyPlayer
// Unit id: 528 of class Marksman in platoon id: 526 for player MyPlayer
// Unit id: 532 of class Marksman in platoon id: 530 for player MyPlayer
// Unit id: 536 of class Marksman in platoon id: 534 for player MyPlayer
// Try removing the set_var call, this will cause the iterator to return
// all units in all platoons for all players.
}
#[cfg(feature = "flecs_nightly_tests")]
#[test]
fn test() {
let output_capture = OutputCapture::capture().unwrap();
main();
output_capture.test("query_setting_variables".to_string());
}