unlit3dx_examples/scene/tick.rs
1//! The behaviour that ticks a gameplay object.
2//!
3//! A tick is dispatched as a frame, so every behaviour in the gameplay world is
4//! an [`OnFrame`]. An object is the component that carries what it owns plus the
5//! behaviour that ticks it, spawned as one bundle, so adding an object to the
6//! scene is spawning an entity and never editing a list.
7//!
8//! Most objects state no order: they tick in the default band, where the
9//! dispatch promises nothing about which of them runs first, and none of them
10//! reads what another writes. The two that do — the balls, which read the
11//! assets built before them, and the panel's publish, which reads what every
12//! object wrote — state an order with [`advancing_in`] at both ends, so the
13//! dependency holds however the setup spawns them.
14//!
15//! The behaviour advances that object's own component, looked up on the entity
16//! the bundle was spawned on. It holds the component exclusively for as long as
17//! it runs, so a tick that reaches for the component it advances a second time
18//! finds it borrowed: everything else a tick reads, it reads through the world
19//! it is handed.
20
21use unlit_ecs::World;
22use unlit3d::frame::{Frame, FrameBehaviourOrder, OnFrame};
23
24/// The behaviour that advances the `T` of the entity it is spawned on.
25///
26/// An object spawns its component and this behaviour as one bundle, so the
27/// component is found on the behaviour's own entity rather than by reaching for
28/// a well-known one, and every run looks it up afresh: the behaviour outlives
29/// no component and borrows none between runs.
30pub(super) fn advancing<T: 'static>(
31 tick: impl FnMut(&mut T, &World, &mut Frame) + 'static,
32) -> OnFrame {
33 advance(FrameBehaviourOrder::default(), tick)
34}
35
36/// The behaviour that advances the `T` of the entity it is spawned on, at
37/// `order`.
38///
39/// For an object whose tick reads what another object's tick writes: the order
40/// is what makes the read see this frame's write, where two ticks in the
41/// default band have no order between them.
42pub(super) fn advancing_in<T: 'static>(
43 order: FrameBehaviourOrder,
44 tick: impl FnMut(&mut T, &World, &mut Frame) + 'static,
45) -> OnFrame {
46 advance(order, tick)
47}
48
49/// `advancing` and `advancing_in` with the order as a parameter.
50fn advance<T: 'static>(
51 order: FrameBehaviourOrder,
52 mut tick: impl FnMut(&mut T, &World, &mut Frame) + 'static,
53) -> OnFrame {
54 OnFrame::with_order(order, move |world, entity, frame| {
55 let _ = world
56 .root_scope()
57 .query_one::<&mut T>(entity)
58 .map(|mut component| tick(component.get(), world, frame));
59 })
60}