lifecycler 0.2.1

Bevy Game Jam #5 submission. Terminal aquarium.
Documentation
use std::time::Duration;

use bevy::{prelude::*, time::common_conditions::on_timer};

use crate::pellets::Pellet;

use super::{
    behavior::{CreatureBehavior, CreatureOperations, CreatureRng},
    snail_behavior::SnailOperations,
};

pub(super) fn plugin(app: &mut App) {
    app.add_systems(Startup, setup_snails_system)
        .add_systems(
            Update,
            (
                spawn_snails_system,
                snails_behavior_system,
                snails_behavior_change_system,
                snails_pellet_detection_system.run_if(on_timer(Duration::from_secs_f32(0.5))),
            ),
        )
        .add_event::<SnailSpawnEvent>();
}

#[derive(Component)]
pub struct Snail;

#[derive(Resource, Deref)]
pub struct SnailScene(Handle<Scene>);

#[derive(Event)]
pub struct SnailSpawnEvent(pub Vec3, pub f32);

fn setup_snails_system(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut spawn_events: EventWriter<SnailSpawnEvent>,
) {
    let snail = asset_server.load(GltfAssetLabel::Scene(0).from_asset("embedded://snail.glb"));
    commands.insert_resource(SnailScene(snail));

    spawn_events.send(SnailSpawnEvent(Vec3::new(-1.4, -1.7, 0.4), 0.1));
    spawn_events.send(SnailSpawnEvent(Vec3::new(1.4, -1.7, -0.1), 0.07));
}

fn spawn_snails_system(
    mut commands: Commands,
    mut spawn_events: EventReader<SnailSpawnEvent>,
    fish_scene: Res<SnailScene>,
) {
    for SnailSpawnEvent(location, size) in spawn_events.read() {
        let transform = Transform::from_translation(*location).with_scale(Vec3::splat(*size));
        let mut behavior = CreatureBehavior::default();
        behavior
            .timer
            .set_duration(behavior.timer.duration() - Duration::from_secs((size * 10.) as u64 % 2));

        commands.spawn((
            Snail,
            behavior,
            SceneBundle {
                transform,
                scene: fish_scene.clone(),
                ..default()
            },
        ));
    }
}

fn snails_behavior_system(
    mut commands: Commands,
    time: Res<Time>,
    mut snails: Query<(&mut Transform, &mut CreatureBehavior), With<Snail>>,
    pellets: Query<(Entity, &mut Transform), (With<Pellet>, Without<CreatureBehavior>)>,
    mut rng: ResMut<CreatureRng>,
) {
    for (mut transform, mut behavior) in snails.iter_mut() {
        SnailOperations::new(&mut transform, &mut behavior).do_behavior(
            &mut commands,
            &mut rng,
            &time,
            &pellets,
        );
    }
}

fn snails_behavior_change_system(
    time: Res<Time>,
    mut snails: Query<(&mut Transform, &mut CreatureBehavior), With<Snail>>,
    mut rng: ResMut<CreatureRng>,
) {
    for (mut transform, mut behavior) in snails.iter_mut() {
        SnailOperations::new(&mut transform, &mut behavior).decide_behavior(&time, &mut rng);
    }
}

fn snails_pellet_detection_system(
    mut snails: Query<(&mut Transform, &mut CreatureBehavior), With<Snail>>,
    pellets: Query<(Entity, &Transform), (With<Pellet>, Without<CreatureBehavior>)>,
) {
    for (mut transform, mut behavior) in snails.iter_mut() {
        SnailOperations::new(&mut transform, &mut behavior).detect_pellet(&pellets);
    }
}