entity_graph/
entity_graph.rs1use bevy_ecs::prelude::*;
13use bevy_entity_ptr::{EntityHandle, EntityPtr, WorldExt};
14
15#[derive(Component)]
18struct Name(&'static str);
19
20#[derive(Component)]
21struct Health(i32);
22
23#[derive(Component)]
24struct Target(Option<EntityHandle>);
25
26#[derive(Component)]
27struct Inventory(Vec<EntityHandle>);
28
29#[derive(Component)]
30struct Equipped {
31 weapon: Option<EntityHandle>,
32 armor: Option<EntityHandle>,
33}
34
35#[derive(Component)]
38struct Weight(f32);
39
40#[derive(Component)]
41struct Damage(i32);
42
43#[derive(Component)]
44struct Defense(i32);
45
46fn total_weight(character: EntityPtr) -> f32 {
48 character
49 .get::<Inventory>()
50 .map(|inv| {
51 inv.0
52 .iter()
53 .filter_map(|h| character.follow_handle(*h).get::<Weight>())
54 .map(|w| w.0)
55 .sum()
56 })
57 .unwrap_or(0.0)
58}
59
60fn equipped_damage(character: EntityPtr) -> Option<i32> {
62 character
63 .get::<Equipped>()
64 .and_then(|e| e.weapon)
65 .and_then(|h| character.follow_handle(h).get::<Damage>())
66 .map(|d| d.0)
67}
68
69fn equipped_defense(character: EntityPtr) -> Option<i32> {
71 character
72 .get::<Equipped>()
73 .and_then(|e| e.armor)
74 .and_then(|h| character.follow_handle(h).get::<Defense>())
75 .map(|d| d.0)
76}
77
78fn target_info(character: EntityPtr) -> Option<(&'static str, i32)> {
80 character
81 .follow_opt::<Target, _>(|t| t.0)
82 .and_then(|target| {
83 let name = target.get::<Name>()?.0;
84 let health = target.get::<Health>()?.0;
85 Some((name, health))
86 })
87}
88
89fn find_attackers(world: &World, target_entity: Entity) -> Vec<EntityPtr> {
91 world
92 .iter_entities()
93 .filter_map(|entity_ref| {
94 let entity = entity_ref.id();
95 let ptr = world.entity_ptr(entity);
96
97 ptr.get::<Target>().and_then(|t| {
99 t.0.filter(|h| h.entity() == target_entity)
100 .map(|_| world.entity_ptr(entity))
101 })
102 })
103 .collect()
104}
105
106fn main() {
107 let mut world = World::new();
108
109 println!("Setting up game entities...\n");
110
111 let sword = world
113 .spawn((Name("Iron Sword"), Weight(5.0), Damage(15)))
114 .id();
115 let shield = world
116 .spawn((Name("Wooden Shield"), Weight(8.0), Defense(10)))
117 .id();
118 let potion = world.spawn((Name("Health Potion"), Weight(0.5))).id();
119 let gold = world.spawn((Name("Gold Coins"), Weight(1.0))).id();
120 let bow = world
121 .spawn((Name("Short Bow"), Weight(3.0), Damage(10)))
122 .id();
123
124 let hero = world
126 .spawn((
127 Name("Hero"),
128 Health(100),
129 Target(None), Inventory(vec![
131 EntityHandle::new(sword),
132 EntityHandle::new(shield),
133 EntityHandle::new(potion),
134 EntityHandle::new(gold),
135 ]),
136 Equipped {
137 weapon: Some(EntityHandle::new(sword)),
138 armor: Some(EntityHandle::new(shield)),
139 },
140 ))
141 .id();
142
143 let goblin = world
145 .spawn((
146 Name("Goblin"),
147 Health(30),
148 Target(Some(EntityHandle::new(hero))),
149 Inventory(vec![EntityHandle::new(bow)]),
150 Equipped {
151 weapon: Some(EntityHandle::new(bow)),
152 armor: None,
153 },
154 ))
155 .id();
156
157 let _orc = world
159 .spawn((
160 Name("Orc"),
161 Health(50),
162 Target(Some(EntityHandle::new(hero))),
163 ))
164 .id();
165
166 let hero_ptr = world.entity_ptr(hero);
168 let goblin_ptr = world.entity_ptr(goblin);
169
170 let weight = total_weight(hero_ptr);
172 println!("Hero's inventory weight: {} lbs", weight);
173 println!(" Expected: 5.0 + 8.0 + 0.5 + 1.0 = 14.5");
174 assert!((weight - 14.5).abs() < 0.01);
175
176 let damage = equipped_damage(hero_ptr);
178 println!("\nHero's equipped weapon damage: {:?}", damage);
179 assert_eq!(damage, Some(15));
180
181 let defense = equipped_defense(hero_ptr);
182 println!("Hero's equipped armor defense: {:?}", defense);
183 assert_eq!(defense, Some(10));
184
185 let goblin_damage = equipped_damage(goblin_ptr);
187 println!("\nGoblin's equipped weapon damage: {:?}", goblin_damage);
188 assert_eq!(goblin_damage, Some(10));
189
190 let goblin_defense = equipped_defense(goblin_ptr);
191 println!("Goblin's equipped armor defense: {:?}", goblin_defense);
192 assert_eq!(goblin_defense, None); let hero_target = target_info(hero_ptr);
196 println!("\nHero's target: {:?}", hero_target);
197 assert_eq!(hero_target, None);
198
199 let goblin_target = target_info(goblin_ptr);
200 println!("Goblin's target: {:?}", goblin_target);
201 assert_eq!(goblin_target, Some(("Hero", 100)));
202
203 let attackers = find_attackers(&world, hero);
205 let attacker_names: Vec<_> = attackers
206 .iter()
207 .filter_map(|p| p.get::<Name>())
208 .map(|n| n.0)
209 .collect();
210 println!("\nEntities targeting the hero: {:?}", attacker_names);
211 assert_eq!(attacker_names.len(), 2);
212 assert!(attacker_names.contains(&"Goblin"));
213 assert!(attacker_names.contains(&"Orc"));
214
215 world
217 .entity_mut(hero)
218 .insert(Target(Some(EntityHandle::new(goblin))));
219
220 let hero_ptr = world.entity_ptr(hero);
222
223 let hero_target = target_info(hero_ptr);
224 println!("\nAfter targeting goblin:");
225 println!("Hero's target: {:?}", hero_target);
226 assert_eq!(hero_target, Some(("Goblin", 30)));
227
228 println!("\nAll assertions passed!");
229}