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