pub struct Turns { /* private fields */ }Expand description
Which entities update this tick, from Ctx::turns.
Implementations§
Source§impl Turns
impl Turns
Sourcepub fn includes(self, entity: Entity) -> bool
pub fn includes(self, entity: Entity) -> bool
true if entity’s turn is this tick.
if ctx.turns(8).includes(e) { /* expensive update */ }Examples found in repository?
examples/ants.rs (line 233)
215fn forage(ctx: &mut Ctx) {
216 let turn = ctx.turns(2);
217 let mut food_grid = SpatialGrid::new(8.0);
218 food_grid.rebuild_from(
219 ctx.world
220 .query::<(Entity, &Transform2D, &Food)>()
221 .iter()
222 .map(|(e, t, _)| (e, t.position)),
223 );
224 let grid = &food_grid;
225 ctx.world
226 .query::<(Entity, &Transform2D, &mut Ant)>()
227 .par_for_each(|(e, t, ant)| {
228 ant.event = Event::None;
229 if ant.energy <= 0.0 {
230 ant.event = Event::Starved;
231 return;
232 }
233 if !turn.includes(e) {
234 return;
235 }
236 let at_home = t.position.distance(ant.home_at) < NEST_RADIUS;
237 if ant.carrying {
238 if at_home {
239 ant.carrying = false;
240 ant.since = 0.0;
241 ant.energy = LIFESPAN;
242 ant.heading += std::f32::consts::PI;
243 ant.event = Event::Delivered;
244 }
245 } else if at_home {
246 ant.since = 0.0;
247 } else if let Some(f) = grid.nearest(t.position, 4.0, |_| true) {
248 ant.carrying = true;
249 ant.since = 0.0;
250 ant.heading += std::f32::consts::PI;
251 ant.event = Event::PickedUp(f.entity);
252 }
253 });
254
255 let (mut picked, mut delivered) = (Vec::new(), Vec::new());
256 let cmds = &mut ctx.commands;
257 ctx.world
258 .query::<(Entity, &Ant)>()
259 .for_each(|(e, ant)| match ant.event {
260 Event::None => {}
261 Event::Starved => cmds.despawn(e),
262 Event::PickedUp(food) => picked.push(food),
263 Event::Delivered => delivered.push(ant.home),
264 });
265 for f in picked {
266 if let Some(food) = ctx.world.get_mut::<Food>(f) {
267 food.amount = food.amount.saturating_sub(1);
268 if food.amount == 0 {
269 ctx.world.despawn(f);
270 }
271 }
272 }
273 for nest in delivered {
274 if let Some(n) = ctx.world.get_mut::<Nest>(nest) {
275 n.stored += 1;
276 n.delivered += 1;
277 }
278 }
279}More examples
examples/battle.rs (line 268)
218fn fight() -> impl FnMut(&mut Ctx) {
219 // Per team: a fine grid for friends (only the closest few matter) and a
220 // coarse one for enemies (seen from afar). Marching armies far from the
221 // enemy then cost almost nothing to search, however packed they are.
222 let mut near = [
223 SpatialGrid::new(PERSONAL_SPACE * 2.0),
224 SpatialGrid::new(PERSONAL_SPACE * 2.0),
225 ];
226 let mut far = [SpatialGrid::new(SIGHT), SpatialGrid::new(SIGHT)];
227 let mut positions: Vec<(Entity, Vec2, Team)> = Vec::new();
228 move |ctx: &mut Ctx| {
229 let (dt, random, look) = (ctx.dt(), ctx.random(), ctx.turns(4));
230 let crowding = ctx.sim_tick().is_multiple_of(2);
231 ctx.world
232 .query::<(Entity, &Transform2D, &Unit)>()
233 .par_collect_into(&mut positions, |(e, t, u)| (e, t.position, u.team));
234 // The four grids are independent: build them at the same time.
235 let [near_red, near_blue] = &mut near;
236 let [far_red, far_blue] = &mut far;
237 let all = &positions;
238 let of = |team: Team| all.iter().filter(move |p| p.2 == team).map(|&(e, at, _)| (e, at));
239 rayon::scope(|s| {
240 if crowding {
241 s.spawn(|_| near_red.rebuild_from(of(Team::Red)));
242 s.spawn(|_| near_blue.rebuild_from(of(Team::Blue)));
243 }
244 s.spawn(|_| far_red.rebuild_from(of(Team::Red)));
245 s.spawn(|_| far_blue.rebuild_from(of(Team::Blue)));
246 });
247 let over = ctx.world.resource::<Score>().winner.is_some();
248 let battle = ctx.world.remove_resource::<Battle>().expect("battle");
249 let (near, far, b) = (&near, &far, &battle);
250 ctx.world
251 .query::<(Entity, &mut Transform2D, &mut Unit)>()
252 .par_for_each(|(e, t, unit)| {
253 let mut rng = random.of(e);
254 let me = t.position;
255 unit.hit = None;
256 unit.cooldown -= dt;
257 if crowding {
258 let mut push = Vec2::ZERO;
259 near[unit.team.index()].for_each_in_radius(me, PERSONAL_SPACE, |other| {
260 if other.entity != e {
261 let away = me - other.position;
262 push += away / (away.length_squared() + 0.01);
263 }
264 });
265 unit.push = push.clamp_length_max(1.0);
266 }
267 let mut nearest = None;
268 if unit.engaged || look.includes(e) {
269 let enemies = &far[unit.team.enemy().index()];
270 nearest = enemies
271 .nearest(me, REACH, |_| true)
272 .or_else(|| enemies.nearest(me, SIGHT, |_| true))
273 .map(|g| (g.position.distance_squared(me), g.entity, g.position));
274 unit.engaged = nearest.is_some();
275 }
276 let enemy_base = b.bases[unit.team.enemy().index()];
277 let mut want = match nearest {
278 Some((d2, target, _)) if d2 < REACH * REACH => {
279 if unit.cooldown <= 0.0 {
280 unit.cooldown = COOLDOWN * rng.range(0.8, 1.2);
281 unit.hit = Some(Hit::Unit(target));
282 }
283 Vec2::ZERO
284 }
285 Some((_, _, at)) => (at - me).normalize_or_zero() * SPEED,
286 None if me.distance(enemy_base) < BASE_RADIUS + REACH => {
287 if unit.cooldown <= 0.0 && !over {
288 unit.cooldown = COOLDOWN;
289 unit.hit = Some(Hit::Base);
290 }
291 Vec2::ZERO
292 }
293 None => b.fields[unit.team.index()].direction_at(me) * SPEED,
294 };
295 let slow = b.nav.cell_at(me).and_then(|c| b.nav.cost(c.x, c.y)).unwrap_or(1).max(1) as f32;
296 want = want / slow + unit.push * SPEED;
297 unit.vel = unit.vel.lerp(want, 0.2) + rng.unit_vec2() * 2.0;
298 // Slide along walls instead of walking into them.
299 let next = me + unit.vel * dt;
300 if b.nav.walkable(next) {
301 t.position = next;
302 } else if b.nav.walkable(vec2(next.x, me.y)) {
303 t.position.x = next.x;
304 } else if b.nav.walkable(vec2(me.x, next.y)) {
305 t.position.y = next.y;
306 }
307 });
308 ctx.world.insert_resource(battle);
309 }
310}Trait Implementations§
impl Copy for Turns
impl StructuralPartialEq for Turns
Auto Trait Implementations§
impl Forget for Turns
impl Freeze for Turns
impl RefUnwindSafe for Turns
impl Send for Turns
impl Sync for Turns
impl Unpin for Turns
impl UnsafeUnpin for Turns
impl UnwindSafe for Turns
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Component for T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Converts
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Converts
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Converts
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Converts
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
impl<T> MaybeSync for T
impl<T> MaybeSync for T
Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<T> Scalar for T
impl<T> SerializableAny for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
The inverse inclusion map: attempts to construct
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
Checks if
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
Use with care! Same as
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
The inclusion map: converts
self to the equivalent element of its superset.