Commit: 08b0390
Parent: 16d70fa

Add a goal

Mårten Åsberg committed on 2026-04-18 at 13:55
docs/screenshot.png +0 -0
diff --git a/docs/screenshot.png b/docs/screenshot.png
index d2bd5e9..ace83be 100644
Binary files a/docs/screenshot.png and b/docs/screenshot.png differ
src/bunnies/bunny.rs +8 -7
diff --git a/src/bunnies/bunny.rs b/src/bunnies/bunny.rs
index d3e0f00..df25151 100644
@@ -24,7 +24,7 @@ use crate::{
Rng,
bunnies::{
heart::{add_heart_system, spawn_heart},
locator::Locator,
locator::BunnyLocator,
},
dog::Dog,
obstacles::Obstacles,
@@ -37,7 +37,7 @@ pub(super) fn add_bunny_systems(app: &mut App) -> &mut App {
}
#[derive(Component)]
pub(super) struct Bunny;
pub struct Bunny;
#[derive(Component)]
enum JumpState {
@@ -100,7 +100,7 @@ fn calculate(mut commands: Commands, mut bunnies: Query<Entity, IdleBunnyFilter>
fn calculate_next_move(
In(bunny): In<Entity>,
mut commands: Commands,
locator: Res<Locator>,
locator: Res<BunnyLocator>,
dog: Single<&Transform, With<Dog>>,
transforms: Query<&mut Transform, Without<Dog>>,
) {
@@ -148,11 +148,12 @@ fn jump_away_from_dog(
}
fn is_near_others(
locator: &Locator,
locator: &BunnyLocator,
bunny: Entity,
bunny_transform: &Transform,
) -> Option<Vec<(Entity, (Vec3, Dir3))>> {
let nearby_bunnies = locator.get_nearby(bunny, bunny_transform.translation, DETECTION_DISTANCE);
let nearby_bunnies =
locator.get_nearby_except_self(bunny, bunny_transform.translation, DETECTION_DISTANCE);
if nearby_bunnies.is_empty() {
None
} else {
@@ -302,7 +303,7 @@ fn look_for_partner(
mut commands: Commands,
bunnies: Query<(Entity, &mut Transform), IdleBunnyFilter>,
time: Res<Time>,
locator: Res<Locator>,
locator: Res<BunnyLocator>,
mut rng: ResMut<Rng>,
) {
bunnies.iter().for_each(|(bunny, bunny_transform)| {
@@ -311,7 +312,7 @@ fn look_for_partner(
}
let Some((partner, _)) = locator
.get_nearby(bunny, bunny_transform.translation, BREED_DISTANCE)
.get_nearby_except_self(bunny, bunny_transform.translation, BREED_DISTANCE)
.drain(..)
.find(|(_, (p, _))| bunny_transform.translation.x < p.x)
else {
src/bunnies/locator.rs +15 -5
diff --git a/src/bunnies/locator.rs b/src/bunnies/locator.rs
index 4fea78a..875c032 100644
@@ -15,27 +15,37 @@ use bevy::{
use crate::bunnies::bunny::Bunny;
pub fn add_locator(app: &mut App) -> &mut App {
app.init_resource::<Locator>()
app.init_resource::<BunnyLocator>()
.add_systems(PreUpdate, update_locator)
}
fn update_locator(mut locator: ResMut<Locator>, bunnies: Query<(Entity, &Transform), With<Bunny>>) {
fn update_locator(
mut locator: ResMut<BunnyLocator>,
bunnies: Query<(Entity, &Transform), With<Bunny>>,
) {
bunnies
.iter()
.for_each(|(bunny, transform)| locator.set(bunny, transform.translation, transform.back()));
}
#[derive(Resource, Default)]
pub(super) struct Locator {
pub struct BunnyLocator {
bunnies: HashMap<Entity, (Vec3, Dir3)>,
}
impl Locator {
impl BunnyLocator {
fn set(&mut self, bunny: Entity, position: Vec3, direction: Dir3) {
self.bunnies.insert(bunny, (position, direction));
}
pub(super) fn get_nearby(
pub fn get_nearby_count(&self, center: Vec3, radius: f32) -> usize {
self.bunnies
.iter()
.filter(|(_, (pos, _))| center.distance(*pos) <= radius)
.count()
}
pub(super) fn get_nearby_except_self(
&self,
this: Entity,
center: Vec3,
src/bunnies/mod.rs +3 -0
diff --git a/src/bunnies/mod.rs b/src/bunnies/mod.rs
index fcf2192..e2fd738 100644
@@ -6,6 +6,9 @@ use bevy::app::App;
use crate::bunnies::{bunny::add_bunny_systems, locator::add_locator};
pub use bunny::Bunny;
pub use locator::BunnyLocator;
pub trait BunnySystems {
fn add_bunny_systems(&mut self) -> &mut Self;
}
src/goal.rs +86 -0
diff --git a/src/goal.rs b/src/goal.rs
new file mode 100644
index 0000000..6e92ff4
@@ -0,0 +1,86 @@
use bevy::{
app::{App, Startup, Update},
asset::Assets,
color::Color,
ecs::{
component::Component,
query::With,
system::{Commands, Query, Res, ResMut, Single},
},
math::{Quat, primitives::Circle},
mesh::{Mesh, Mesh3d},
pbr::{MeshMaterial3d, StandardMaterial},
text::{TextFont, TextSpan},
transform::components::Transform,
ui::widget::Text,
};
use rand::RngExt;
use crate::{
Rng,
bunnies::{Bunny, BunnyLocator},
};
pub trait GoalSystems {
fn add_goal_systems(&mut self) -> &mut Self;
}
impl GoalSystems for App {
fn add_goal_systems(&mut self) -> &mut Self {
self.add_systems(Startup, setup).add_systems(Update, update)
}
}
const GOAL_RADIUS: f32 = 5.0;
#[derive(Component)]
struct Goal;
#[derive(Component)]
struct GoalText;
fn setup(
mut rng: ResMut<Rng>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Mesh3d(meshes.add(Circle::new(GOAL_RADIUS))),
MeshMaterial3d(materials.add(Color::linear_rgb(0.0, 1.0, 0.0))),
Transform::from_xyz(
rng.random_range(-25.0..=25.0),
0.0,
rng.random_range(-25.0..=25.0),
)
.with_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
Goal,
));
commands
.spawn((
Text::new("Bunnies in goal: "),
TextFont {
font_size: 42.0,
..Default::default()
},
))
.with_child((
TextSpan::default(),
TextFont {
font_size: 33.0,
..Default::default()
},
GoalText,
));
}
fn update(
locator: Res<BunnyLocator>,
bunnies: Query<(), With<Bunny>>,
goal: Single<&Transform, With<Goal>>,
mut goal_text: Single<&mut TextSpan, With<GoalText>>,
) {
let count = bunnies.count();
let in_goal = locator.get_nearby_count(goal.translation, GOAL_RADIUS);
**goal_text = format!("{in_goal}/{count}").into();
}
src/main.rs +3 -2
diff --git a/src/main.rs b/src/main.rs
index bd3d2fe..1cb0fc0 100644
@@ -1,5 +1,6 @@
mod bunnies;
mod dog;
mod goal;
mod obstacles;
use bevy::{
@@ -22,8 +23,7 @@ use bevy::{
use rand::SeedableRng;
use rand_chacha::ChaCha8Rng;
use crate::bunnies::BunnySystems;
use crate::dog::DogSystems;
use crate::{bunnies::BunnySystems, dog::DogSystems, goal::GoalSystems};
fn main() {
App::new()
@@ -32,6 +32,7 @@ fn main() {
.init_resource::<Rng>()
.add_dog_systems()
.add_bunny_systems()
.add_goal_systems()
.run();
}