diff --git a/assets/sprites/ant_walk_anim.png b/assets/sprites/ant_walk_anim.png new file mode 100644 index 0000000..1001882 Binary files /dev/null and b/assets/sprites/ant_walk_anim.png differ diff --git a/src/components/ant.rs b/src/components/ant.rs index 09c7580..9adcc88 100644 --- a/src/components/ant.rs +++ b/src/components/ant.rs @@ -1,5 +1,11 @@ -use super::common::{Position, RandomizedVelocity}; +use super::common::{ + AnimationIndices, AnimationTimer, Position, RandomizedVelocityChange, Velocity, + VelocityChangeTimer, +}; +use crate::{ANT_ANIMATION_SPEED, VELOCITY_CHANGE_PERIOD, VELOCITY_CHANGE_SCALE}; use bevy::prelude::*; +use rand::Rng; +use std::f32::consts::PI; /// This bundle represents the ant entity. /// The ``state`` determines the ant's behavior, it stores its current ``position`` @@ -13,7 +19,14 @@ use bevy::prelude::*; pub struct AntBundle { pub state: AntState, pub position: Position, - pub velocity: RandomizedVelocity, + pub velocity: Velocity, + pub velocity_change: RandomizedVelocityChange, + // TODO: This timer is only needed once + pub velocity_change_timer: VelocityChangeTimer, + pub texture_atlas: TextureAtlas, + pub animation_indices: AnimationIndices, + // TODO: This timer is only needed once + pub animation_timer: AnimationTimer, // These are not components, but other bundles of components. Those can be nested. pub sprite: SpriteBundle, @@ -42,17 +55,37 @@ pub enum AntState { // The "impl" keyword allows us to implement functions in a struct's namespace, i.e. "methods" impl AntBundle { /// Instantiate a new ``AntBundle`` with a color and a starting position. - pub fn new(position: Vec2, color: Color) -> Self { + pub fn new( + position: Vec2, + texture: Handle, + texture_atlas: TextureAtlas, + animation_indices: AnimationIndices, + scale: Vec2, + ) -> Self { Self { state: AntState::Searching, position: Position(position), - velocity: RandomizedVelocity(Vec2::ZERO), + velocity: Velocity(rand::thread_rng().gen_range(-PI..PI)), + velocity_change: RandomizedVelocityChange( + rand::thread_rng().gen_range(-1.0..1.0) * VELOCITY_CHANGE_SCALE, + ), + velocity_change_timer: VelocityChangeTimer(Timer::from_seconds( + VELOCITY_CHANGE_PERIOD, + TimerMode::Repeating, + )), + texture_atlas, + animation_indices, + animation_timer: AnimationTimer(Timer::from_seconds( + ANT_ANIMATION_SPEED, + TimerMode::Repeating, + )), sprite: SpriteBundle { transform: Transform { - scale: Vec3::new(20., 20., 20.), + translation: position.extend(0.), + scale: scale.extend(1.), ..default() }, - sprite: Sprite { color, ..default() }, + texture, ..default() }, } diff --git a/src/components/common.rs b/src/components/common.rs index 5e14eef..f660cc7 100644 --- a/src/components/common.rs +++ b/src/components/common.rs @@ -4,7 +4,19 @@ use bevy::prelude::*; pub struct Position(pub Vec2); #[derive(Component)] -pub struct Velocity(pub Vec2); +pub struct Velocity(pub f32); #[derive(Component)] -pub struct RandomizedVelocity(pub Vec2); +pub struct RandomizedVelocityChange(pub f32); + +#[derive(Component)] +pub struct AnimationIndices { + pub first: usize, + pub last: usize, +} + +#[derive(Component)] +pub struct AnimationTimer(pub Timer); + +#[derive(Component)] +pub struct VelocityChangeTimer(pub Timer); diff --git a/src/main.rs b/src/main.rs index b5ba554..75cf4bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,24 +4,33 @@ mod systems; use bevy::prelude::*; use std::f32::consts::PI; use systems::{ - random_walk::{random_walk_system, randomized_velocity_system, wall_avoidance_system}, + ant::{ + animation_system, position_update_system, randomized_velocity_change_system, + randomized_velocity_system, wall_avoidance_system, + }, startup::{hello_ants_system, setup_system}, }; // TODO: Use Settings Resource -const MIN_POSITION: Vec2 = Vec2::ZERO; -const MAX_POSITION: Vec2 = Vec2::new(500., 500.); +const MIN_POSITION: Vec2 = Vec2::splat(-450.); +const MAX_POSITION: Vec2 = Vec2::splat(450.); -const ANT_COUNT: u32 = 25; -const ANT_SPEED: f32 = 0.75; -const RANDOM_WALK_CONE: f32 = PI / 180. * 20.; +const ANT_COUNT: u32 = 200; +const ANT_SPEED: f32 = 0.5; +const ANT_ANIMATION_SPEED: f32 = 1. / 62.; +const ANT_SCALE: f32 = 0.15; + +const VELOCITY_CHANGE_SCALE: f32 = PI / 180. * 1.; // Single degree +const VELOCITY_CHANGE_MAX: f32 = PI / 180. * 0.5; +const VELOCITY_CHANGE_PERIOD: f32 = 0.5; /// The app's entrypoint. fn main() { let mut app = App::new(); // The DefaultPlugins contain the "Window" plugin. - app.add_plugins(DefaultPlugins); + // ImagePlugin::default_nearest() is supposed to prevent blurry sprites. + app.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())); // Sets the color used to clear the screen, i.e. the background color. app.insert_resource(ClearColor(Color::srgb(0.9, 0.9, 0.9))); @@ -38,9 +47,11 @@ fn main() { app.add_systems( FixedUpdate, ( + randomized_velocity_change_system, randomized_velocity_system, wall_avoidance_system, - random_walk_system, + position_update_system, + animation_system, ) .chain(), ); diff --git a/src/systems/ant.rs b/src/systems/ant.rs new file mode 100644 index 0000000..9656c8f --- /dev/null +++ b/src/systems/ant.rs @@ -0,0 +1,96 @@ +use crate::{ + components::common::{ + AnimationIndices, AnimationTimer, Position, RandomizedVelocityChange, Velocity, + VelocityChangeTimer, + }, + ANT_SPEED, MAX_POSITION, MIN_POSITION, VELOCITY_CHANGE_MAX, VELOCITY_CHANGE_SCALE, +}; +use bevy::prelude::*; +use rand::Rng; +use std::f32::consts::PI; + +/// Randomizes the ``RandomizeVelocityChange`` components. +#[allow(clippy::needless_pass_by_value)] +pub fn randomized_velocity_change_system( + mut query: Query<(&mut RandomizedVelocityChange, &mut VelocityChangeTimer)>, + time: Res