Skip to content

Commit

Permalink
refactor: encapsulate funcionalities (#5)
Browse files Browse the repository at this point in the history
* wip: create plugins

* refactor: separate logic into files

* fix: structure
  • Loading branch information
fborello-lambda authored Jul 19, 2024
1 parent 4c1b77a commit a02f17e
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 113 deletions.
56 changes: 56 additions & 0 deletions src/algae.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use crate::components::*;
use crate::resources::*;
use bevy::prelude::*;
use rand::*;

#[derive(Component)]
pub struct Algae;
#[derive(Bundle)]
pub struct AlgaeBundle {
pub(crate) position: Position,
pub(crate) sprite: SpriteBundle,
pub(crate) algae_component: Algae,
}

pub struct AlgaePlugin;
impl Plugin for AlgaePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, algae_setup)
.add_systems(Update, algae_update);
}
}

fn algae_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
for _ in 0..10 {
let start_pos = Vec2::new(
rand::thread_rng().gen_range(-300.0..300.0),
rand::thread_rng().gen_range(-300.0..300.0),
);
commands.spawn(AlgaeBundle {
algae_component: Algae,
position: Position { v2: start_pos },
sprite: SpriteBundle {
texture: asset_server.load("embedded://fish-forage/algae.png"),
transform: Transform::from_scale(Vec3::splat(1.)),
..default()
},
});
}
}

fn algae_update(
time: Res<Time>,
mut timer: ResMut<ChangeObjectiveTimer>,
mut algae_query: Query<(&mut Transform, &mut Position), With<Algae>>,
) {
if timer.0.tick(time.delta()).finished() {
for (mut transform, mut position) in &mut algae_query {
let new_pos = Vec2::new(
rand::thread_rng().gen_range(-300.0..300.0),
rand::thread_rng().gen_range(-300.0..300.0),
);
transform.translation = Vec3::new(new_pos.x, new_pos.y, 0.);
position.v2 = new_pos;
}
}
}
16 changes: 16 additions & 0 deletions src/components.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use bevy::prelude::*;

#[derive(Component, Debug, Clone, Copy, PartialEq)]
pub struct Velocity {
pub v2: Vec2,
}

#[derive(Component, Debug, Clone, Copy, PartialEq)]
pub struct Position {
pub v2: Vec2,
}

#[derive(Component, Debug, Clone, Copy, PartialEq)]
pub struct Objective {
pub v2: Vec2,
}
82 changes: 82 additions & 0 deletions src/fish.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use bevy::{math::bounding::Aabb2d, prelude::*};
use rand::*;

use crate::components::*;

#[derive(Component)]
pub struct Fish;
#[derive(Bundle)]
pub struct FishBundle {
pub(crate) velocity: Velocity,
pub(crate) position: Position,
pub(crate) objective: Objective,
pub(crate) sprite: SpriteBundle,
pub(crate) fish_component: Fish,
}

pub struct FishPlugin;
impl Plugin for FishPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, fish_setup)
.add_systems(Update, fish_update);
}
}

fn fish_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
for _ in 0..10 {
let start_pos = Vec2::new(
rand::thread_rng().gen_range(-300.0..300.0),
rand::thread_rng().gen_range(-300.0..300.0),
);
commands.spawn(FishBundle {
position: Position { v2: start_pos },
velocity: Velocity { v2: Vec2::ZERO },
objective: Objective { v2: start_pos },
sprite: SpriteBundle {
texture: asset_server.load("embedded://fish-forage/fish-sardine.png"),
transform: Transform::from_scale(Vec3::splat(2.)),
..default()
},
fish_component: Fish,
});
}
}

fn fish_update(
time: Res<Time>,
windows: Query<&Window>,
algae_query: Query<&Position, Without<Fish>>,
mut fish_query: Query<
(&mut Velocity, &mut Position, &mut Objective, &mut Transform),
With<Fish>,
>,
) {
let window = windows.single();
let window_size = window.size();
let collision_area = Aabb2d::new(Vec2::ZERO, (window_size - 5.0) / 2.);

let mut algae_iter = algae_query.iter();

for (mut v, mut p, mut o, mut transform) in &mut fish_query {
if let Some(algae_position) = algae_iter.next() {
o.v2 = algae_position.v2;
} else {
// If there are more fish than algae, reset the algae iterator
algae_iter = algae_query.iter();
if let Some(algae_position) = algae_iter.next() {
o.v2 = algae_position.v2;
}
}

p.v2 += v.v2 * time.delta_seconds();
p.v2.x = p.v2.x.clamp(collision_area.min.x, collision_area.max.x);
p.v2.y = p.v2.y.clamp(collision_area.min.y, collision_area.max.y);

let acc = 100. * (o.v2 - p.v2).normalize_or_zero();
v.v2 += acc * time.delta_seconds();

v.v2 = v.v2.clamp_length_max(80.);

transform.translation = Vec3::new(p.v2.x, p.v2.y, 0.);
}
}
127 changes: 14 additions & 113 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,124 +1,25 @@
use std::time::Duration;
use bevy::prelude::*;
use bevy_embedded_assets::*;

use bevy::{math::bounding::Aabb2d, prelude::*};
use bevy_embedded_assets::EmbeddedAssetPlugin;
use rand::Rng;
mod algae;
mod components;
mod fish;
mod resources;
use algae::*;
use fish::*;
use resources::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(EmbeddedAssetPlugin::default())
.add_systems(Startup, setup)
.add_systems(Update, (swim, move_algae))
.insert_resource(ChangeObjectiveTimer(Timer::from_seconds(
5.0,
TimerMode::Repeating,
)))
.add_systems(Startup, camera_setup)
.add_plugins(FishPlugin)
.add_plugins(AlgaePlugin)
.add_plugins(TimerPlugin)
.run();
}

#[derive(Component)]
struct Swimmer {
position: Vec2,
velocity: Vec2,
objective: Vec2,
}

#[derive(Resource)]
struct ChangeObjectiveTimer(Timer);

#[derive(Component)]
struct Algae;

fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut timer: ResMut<ChangeObjectiveTimer>,
) {
timer.0.tick(Duration::from_secs_f32(4.9));

fn camera_setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
for _ in 0..10 {
let start_pos = Vec2::new(
rand::thread_rng().gen_range(-300.0..300.0),
rand::thread_rng().gen_range(-300.0..300.0),
);
commands.spawn((
SpriteBundle {
texture: asset_server.load("embedded://fish-forage/fish-sardine.png"),
transform: Transform::from_scale(Vec3::splat(2.)),
..default()
},
Swimmer {
position: start_pos,
velocity: Vec2::ZERO,
objective: start_pos,
},
));
}

commands.spawn((
SpriteBundle {
texture: asset_server.load("embedded://fish-forage/algae.png"),
transform: Transform::from_scale(Vec3::splat(2.)),
..default()
},
Algae,
));
}

fn swim(
time: Res<Time>,
windows: Query<&Window>,
mut fish_query: Query<(&mut Swimmer, &mut Transform)>,
) {
let window = windows.single();
let window_size = window.size();
let collision_area = Aabb2d::new(Vec2::ZERO, (window_size - 5.0) / 2.);

for (mut swimmer, mut transform) in &mut fish_query {
let v = swimmer.velocity;
swimmer.position += v * time.delta_seconds();

swimmer.position.x = swimmer
.position
.x
.clamp(collision_area.min.x, collision_area.max.x);
swimmer.position.y = swimmer
.position
.y
.clamp(collision_area.min.y, collision_area.max.y);

let acc = 100. * (swimmer.objective - swimmer.position).normalize_or_zero();
swimmer.velocity += acc * time.delta_seconds();

swimmer.velocity = swimmer.velocity.clamp_length_max(80.);

transform.translation = Vec3::new(swimmer.position.x, swimmer.position.y, 0.);

// println!(
// "position: {:?}, velocity: {:?}",
// swimmer.position, swimmer.velocity
// );
}
}

fn move_algae(
time: Res<Time>,
mut timer: ResMut<ChangeObjectiveTimer>,
mut swimmer_query: Query<&mut Swimmer>,
mut algae_query: Query<&mut Transform, With<Algae>>,
) {
if timer.0.tick(time.delta()).just_finished() {
for mut algae in &mut algae_query {
let new_pos = Vec2::new(
rand::thread_rng().gen_range(-300.0..300.0),
rand::thread_rng().gen_range(-300.0..300.0),
);
algae.translation = Vec3::new(new_pos.x, new_pos.y, 0.);
for mut swimmer in &mut swimmer_query {
swimmer.objective = new_pos;
}
}
}
}
21 changes: 21 additions & 0 deletions src/resources.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use bevy::prelude::*;
use std::time::Duration;

#[derive(Resource)]
pub struct ChangeObjectiveTimer(pub Timer);

pub struct TimerPlugin;

impl Plugin for TimerPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(ChangeObjectiveTimer(Timer::from_seconds(
5.0,
TimerMode::Repeating,
)))
.add_systems(Update, update_timer);
}
}

fn update_timer(mut timer: ResMut<ChangeObjectiveTimer>) {
timer.0.tick(Duration::from_secs_f32(5.0));
}

0 comments on commit a02f17e

Please sign in to comment.