--- name: bevy-game-loop-harvest description: "Bevy ECS harvest loop: Crop stage on Time, season scale, catch-up from a LastVisit resource, Harvested messages. Use when growth must finish before the yield message. Keywords: Bevy, harvest, crop, FixedUpdate, season, catch-up." --- # Bevy harvest loop ## When to use Load this when crops advance on a timer and a harvest message records the yield. ## ECS shape - **Components:** growth elapsed and a stage index you define. - **Resources:** the last visit and the season scale live in resources (bevy-data-resources). - **Systems:** step growth on `FixedUpdate`. Use `.chain()` so harvest reads the stage growth just wrote. - **Messages:** `Harvested` is the one-shot yield fact. Inventory applies it in bevy-inventory-system. ## Idioms | Need | Bevy shape | | --- | --- | | Growth | Elapsed time on a component, stepped on the fixed clock. | | Extract | A `Harvested` message. Inventory consumes it. | | Season | A resource scale. No calendar type was opened. | ## Scope - A crop component stores stage and elapsed time. Growth steps on `Time`. - Offline catch-up reads `Time::elapsed_secs` against a resource that remembers the last visit. ## Examples ```toml [package] name = "harvest" version = "0.1.0" edition = "2021" [dependencies] bevy = "0.20" ``` Growth advances one stage per interval. Harvest only fires when the last stage is ready. ```rust #[derive(Component)] struct Crop { stage: u8, elapsed: f32, stage_seconds: f32, stages: u8, } #[derive(Message)] struct Harvested { plot: Entity, yield_item: u32, } fn grow(time: Res>, mut crops: Query<&mut Crop>) { let dt = time.delta_secs(); for mut crop in &mut crops { if crop.stage + 1 >= crop.stages { continue; } crop.elapsed += dt; if crop.elapsed >= crop.stage_seconds { crop.elapsed = 0.0; crop.stage += 1; } } } fn harvest( mut commands: Commands, crops: Query<(Entity, &Crop)>, mut harvested: MessageWriter, ) { for (entity, crop) in &crops { if crop.stage + 1 < crop.stages { continue; } harvested.write(Harvested { plot: entity, yield_item: 7, }); commands.entity(entity).despawn(); } } pub struct HarvestPlugin; impl Plugin for HarvestPlugin { fn build(&self, app: &mut App) { app.add_message::() .add_systems(FixedUpdate, (grow, harvest).chain()); } } ``` Catch-up applies the seconds since the last recorded visit, then stores the new mark. ```rust #[derive(Component)] struct Crop { stage: u8, elapsed: f32, stage_seconds: f32, stages: u8, } #[derive(Resource)] struct LastVisit { elapsed_secs: f32, } fn catch_up(time: Res