Skip to content

Commit

Permalink
add flock entity with naive flock behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
reeceyang committed Dec 29, 2023
1 parent dcc98b1 commit dffd9bb
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 32 deletions.
3 changes: 2 additions & 1 deletion native_app/src/gui/selectable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ pub fn select_radius(id: AnyEntity) -> f32 {
AnyEntity::FreightStationID(_) => 0.0,
AnyEntity::CompanyID(_) => 0.0,
AnyEntity::HumanID(_) => 3.0,
AnyEntity::BirdID(_) => 3.0,
// TODO: make the radius smaller after finishing testing
AnyEntity::BirdID(_) => 20.0,
}
}

Expand Down
4 changes: 2 additions & 2 deletions simulation/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::transportation::train::{
};
use crate::utils::resources::Resources;
use crate::utils::time::Tick;
use crate::wildlife::add_birds_randomly;
use crate::wildlife::add_flocks_randomly;
use crate::wildlife::bird::bird_decision_system;
use crate::world::{CompanyEnt, FreightStationEnt, HumanEnt, TrainEnt, VehicleEnt, WagonEnt};
use crate::World;
Expand Down Expand Up @@ -49,7 +49,7 @@ pub fn init() {
register_system("random_vehicles", random_vehicles_update);

register_system_sim("add_souls_to_empty_buildings", add_souls_to_empty_buildings);
register_system_sim("add_birds_randomly", add_birds_randomly);
register_system_sim("add_birds_randomly", add_flocks_randomly);

register_resource_noserialize::<GoodsCompanyRegistry>();
register_resource_noserialize::<ItemRegistry>();
Expand Down
60 changes: 52 additions & 8 deletions simulation/src/wildlife/bird.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,38 @@ pub fn bird_decision_system(world: &mut World, resources: &mut Resources) {
let aabb = map.terrain.bounds();

Check failure on line 62 in simulation/src/wildlife/bird.rs

View workflow job for this annotation

GitHub Actions / build

no field `terrain` on type `&map::map::Map`
let r = &mut RandProvider::new(ra.timestamp as u64);

world.birds
.values_mut()
//.par_bridge()
.for_each(|bird| bird_decision(ra, &mut bird.it, &mut bird.trans, &mut bird.speed, &mut bird.bird_mob, aabb, r))
world.flocks.values().for_each(|flock| {
let flock_physics: Vec<(Transform, Speed)> = flock
.bird_ids
.iter()
.map(|bird_id| match world.birds.get_mut(*bird_id) {
Some(bird_ent) => (bird_ent.trans, bird_ent.speed.clone()),
None => unreachable!(),
})
.collect();

flock
.bird_ids
.iter()
.for_each(|bird_id| match world.birds.get_mut(*bird_id) {
Some(bird_ent) => bird_decision(
ra,
&mut bird_ent.it,
&mut bird_ent.trans,
&mut bird_ent.speed,
&mut bird_ent.bird_mob,
aabb,
r,
&flock_physics,
),
None => unreachable!(),
})
});

// world.birds
// .values_mut()
// //.par_bridge()
// .for_each(|bird| bird_decision(ra, &mut bird.it, &mut bird.trans, &mut bird.speed, &mut bird.bird_mob, aabb, r))
}

const BIRD_WAIT_TIME: f64 = 100.0;
Expand All @@ -88,7 +116,7 @@ pub fn get_random_pos_from_center(center: Vec3, radius: f32, r1: f32, r2: f32, r
}

// amount of time per each flock itinerary
const FLOCK_IT_PERIOD: f32 = 100000.0;
const FLOCK_IT_PERIOD: f32 = 20000.0;
// likelihood the bird will stray from the flock itinerary
const DISTRACTED_PROB: f32 = 0.5;

Expand All @@ -100,6 +128,7 @@ pub fn bird_decision(
bird_mob: &mut BirdMob,
aabb: AABB,
r: &mut RandProvider,
flock_physics: &Vec<(Transform, Speed)>,
) {
let (desired_v, desired_dir) = calc_decision(bird_mob, trans, it);

Expand All @@ -110,7 +139,7 @@ pub fn bird_decision(
// a random nearby location to hang around
let random_itinerary = Itinerary::simple(vec![get_random_pos_from_center(
trans.position,
5.0,
100.0,
r.next_f32(),
r.next_f32(),
r.next_f32(),
Expand Down Expand Up @@ -160,10 +189,19 @@ pub fn physics(
kin.0 += mag;
}
const ANG_VEL: f32 = 1.0;
// log::info!("{} {}", trans.dir, desired_dir);
assert!(
desired_dir.xy().mag() != 0.0,
"desired_dir.xy() had 0 magnitude"
);
trans.dir = angle_lerpxy(trans.dir, desired_dir, ANG_VEL * time.realdelta);
}

pub fn calc_decision(bird_mob: &mut BirdMob, trans: &Transform, it: &Itinerary) -> (f32, Vec3) {
assert!(
trans.dir.xy().mag() != 0.0,
"trans.dir.xy() had 0 magnitude"
);
let objective = match it.get_point() {
Some(x) => x,
None => return (0.0, trans.dir),
Expand All @@ -172,11 +210,17 @@ pub fn calc_decision(bird_mob: &mut BirdMob, trans: &Transform, it: &Itinerary)
let position = trans.position;

let delta_pos: Vec3 = objective - position;
let dir_to_pos = match delta_pos.try_normalize() {
Some(x) => x,
let dir_to_pos = match delta_pos.xy().try_normalize() {
Some(x) => x.z(trans.dir.z),
None => return (0.0, trans.dir),
};

// log::info!("calc_decision trans.dir {}", trans.dir);
// log::info!("calc_decision dir_to_pos {}", dir_to_pos);
let desired_dir = dir_to_pos.normalize();
assert!(
desired_dir.xy().mag() != 0.0,
"desired_dir.xy() had 0 magnitude in calc_decision"
);
(bird_mob.flying_speed, desired_dir)
}
49 changes: 28 additions & 21 deletions simulation/src/wildlife/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,42 @@ use crate::utils::rand_provider::RandProvider;
use crate::wildlife::bird::{
get_random_bird_pos, get_random_pos_from_center, spawn_bird, NUM_FLOCKS,
};
use crate::Simulation;
use common::rand::{rand, rand2, rand3};
use crate::{BirdID, Flock, Simulation};

pub mod bird;

const NUM_BIRDS: u32 = 1000;
const BIRDS_PER_FLOCK: u32 = 50;
const DIST_SPREAD: f32 = 5.0; // how large of a radius to initially spawn birds

/// HACK (for now): spawns birds in random clusters around the map
pub(crate) fn add_birds_randomly(sim: &mut Simulation) {
profiling::scope!("wildlife::add_birds_randomly");
pub(crate) fn add_flocks_randomly(sim: &mut Simulation) {
profiling::scope!("wildlife::add_flocks_randomly");

let num_birds = sim.world().birds.len();
if num_birds > NUM_BIRDS as usize {
let num_flocks = sim.world().flocks.len();
if num_flocks >= NUM_FLOCKS as usize {
return;
}

let mut rng = RandProvider::new(num_flocks as u64);

let aabb = sim.map().terrain.bounds();

Check failure on line 23 in simulation/src/wildlife/mod.rs

View workflow job for this annotation

GitHub Actions / build

no field `terrain` on type `resources::Ref<'_, map::map::Map>`
let seed = (num_birds as u32 / (NUM_BIRDS / NUM_FLOCKS)) as f32;
let cluster_pos =
get_random_bird_pos(aabb, rand(seed), rand2(seed, seed), rand3(seed, seed, seed));

let mut rng = RandProvider::new(num_birds as u64);

let home_pos = get_random_pos_from_center(
cluster_pos,
5.0,
rng.next_f32(),
rng.next_f32(),
rng.next_f32(),
);
spawn_bird(sim, home_pos);
let center_pos = get_random_bird_pos(aabb, rng.next_f32(), rng.next_f32(), rng.next_f32());

let mut ids: Vec<BirdID> = Vec::new();

for _ in 0..BIRDS_PER_FLOCK {
let bird_pos = get_random_pos_from_center(
center_pos,
DIST_SPREAD,
rng.next_f32(),
rng.next_f32(),
rng.next_f32(),
);
match spawn_bird(sim, bird_pos) {
Some(id) => ids.push(id),
None => (),
}
}

sim.world.insert(Flock { bird_ids: ids });
}
9 changes: 9 additions & 0 deletions simulation/src/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ new_key_type! {
pub struct FreightStationID;
pub struct CompanyID;
pub struct BirdID;
pub struct FlockID;
}

impl_entity!(VehicleID, VehicleEnt, vehicles);
Expand All @@ -38,6 +39,7 @@ impl_entity!(WagonID, WagonEnt, wagons);
impl_entity!(FreightStationID, FreightStationEnt, freight_stations);
impl_entity!(CompanyID, CompanyEnt, companies);
impl_entity!(BirdID, BirdEnt, birds);
impl_entity!(FlockID, Flock, flocks);

impl_trans!(HumanID);
impl_trans!(VehicleID);
Expand Down Expand Up @@ -194,6 +196,11 @@ impl SimDrop for BirdEnt {
fn sim_drop(self, _: BirdID, _: &mut Resources) {}
}

#[derive(Serialize, Deserialize)]
pub struct Flock {
pub bird_ids: Vec<BirdID>,
}

#[derive(Default, Serialize, Deserialize)]
pub struct World {
pub vehicles: HopSlotMap<VehicleID, VehicleEnt>,
Expand All @@ -203,6 +210,7 @@ pub struct World {
pub freight_stations: HopSlotMap<FreightStationID, FreightStationEnt>,
pub companies: HopSlotMap<CompanyID, CompanyEnt>,
pub birds: HopSlotMap<BirdID, BirdEnt>,
pub flocks: HopSlotMap<FlockID, Flock>,
}

impl World {
Expand Down Expand Up @@ -280,6 +288,7 @@ impl World {
self.vehicles.iter().map(|(id, x)| (AnyEntity::VehicleID(id), x.trans.position.xy())),
self.trains .iter().map(|(id, x)| (AnyEntity::TrainID(id), x.trans.position.xy())),
self.wagons .iter().map(|(id, x)| (AnyEntity::WagonID(id), x.trans.position.xy())),
self.birds .iter().map(|(id, x)| (AnyEntity::BirdID(id), x.trans.position.xy())),
))
}

Expand Down

0 comments on commit dffd9bb

Please sign in to comment.