lifecycler 0.2.9

Bevy Game Jam #5 submission, terminal aquarium
Documentation
use std::f32::consts::PI;

use bevy::{ecs::query::QueryEntityError, prelude::*};

use crate::general::AttemptDespawn;

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

pub struct SnailOperations<'a> {
    transform: &'a mut Transform,
    behavior: &'a mut CreatureBehavior,
}

impl<'a> SnailOperations<'a> {
    pub(super) fn new(transform: &'a mut Transform, behavior: &'a mut CreatureBehavior) -> Self {
        Self {
            transform,
            behavior,
        }
    }
}

impl<'a> CreatureOperations for SnailOperations<'a> {
    fn behavior_debut(&mut self, _time: &Time, _rng: &mut CreatureRng) {
        if self.transform.translation.x < 0. {
            self.start_swim_right();
        } else {
            self.start_swim_left();
        }
    }

    fn behavior_idle(&mut self, time: &Time) {
        self.transform.translation.z += time.elapsed_seconds().sin() / 10_000.;
    }

    fn behavior_seek_pellet(
        &mut self,
        time: &Time,
        rng: &mut CreatureRng,
        pellet: Result<(Entity, &Transform), QueryEntityError>,
        commands: &mut Commands,
    ) {
        if let Ok((pellet_entity, pellet_transform)) = pellet {
            if self.transform.translation.x < pellet_transform.translation.x {
                self.face_right();
            } else {
                self.face_left();
            }

            let (min, max) = Self::valid_area();
            self.transform.translation = self.transform.translation.move_towards(
                pellet_transform.translation.clamp(min, max),
                time.delta_seconds() * Self::base_speed() * 2.,
            );

            if self
                .transform
                .translation
                .distance(pellet_transform.translation)
                < 0.1
            {
                if let Some(mut entity) = commands.get_entity(pellet_entity) {
                    entity.insert(AttemptDespawn);
                }
            }
        } else {
            self.start_seek_point(rng);
        }
    }

    fn face_right(&mut self) {
        *self.transform = self.transform.with_rotation(Quat::IDENTITY);
    }

    fn face_left(&mut self) {
        *self.transform = self.transform.with_rotation(Quat::from_rotation_y(PI));
    }

    fn rank_pellet(&mut self, pellet_transform: &Transform) -> f32 {
        self.transform()
            .translation
            .xz()
            .distance(pellet_transform.translation.xy())
    }

    fn check_pellet(&mut self, _rank: f32) -> bool {
        true
    }

    fn base_speed() -> f32 {
        0.05
    }

    fn valid_area() -> (Vec3, Vec3) {
        (Vec3::new(-1.5, -1.7, -0.4), Vec3::new(1.5, -1.7, 0.4))
    }

    fn behavior(&mut self) -> &mut CreatureBehavior {
        self.behavior
    }

    fn transform(&mut self) -> &mut Transform {
        self.transform
    }

    fn valid_point_buffer() -> Vec3 {
        Vec3::new(0.2, 0., 0.)
    }
}