track cursor
This commit is contained in:
parent
af4065e149
commit
96c27d4b0d
5 changed files with 53 additions and 4 deletions
16
src/boids.rs
16
src/boids.rs
|
|
@ -3,6 +3,7 @@ use std::f32::consts::PI;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::ModelConfig,
|
config::ModelConfig,
|
||||||
|
pointer::PointerTarget,
|
||||||
spatial_grid::{SpatialGrid, update_spatial_grid},
|
spatial_grid::{SpatialGrid, update_spatial_grid},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -122,6 +123,7 @@ fn update_boids(
|
||||||
window: Single<&Window, With<bevy::window::PrimaryWindow>>,
|
window: Single<&Window, With<bevy::window::PrimaryWindow>>,
|
||||||
time: Res<Time<Fixed>>,
|
time: Res<Time<Fixed>>,
|
||||||
grid: Res<SpatialGrid>,
|
grid: Res<SpatialGrid>,
|
||||||
|
pointer: Res<PointerTarget>,
|
||||||
mut query: Query<(Entity, &mut Boid, &mut Transform)>,
|
mut query: Query<(Entity, &mut Boid, &mut Transform)>,
|
||||||
) {
|
) {
|
||||||
let dt = time.delta_secs();
|
let dt = time.delta_secs();
|
||||||
|
|
@ -194,8 +196,18 @@ fn update_boids(
|
||||||
// Push each boid forward along its current heading
|
// Push each boid forward along its current heading
|
||||||
let self_force = boid.velocity.normalize_or_zero() * model_config.self_acceleration;
|
let self_force = boid.velocity.normalize_or_zero() * model_config.self_acceleration;
|
||||||
|
|
||||||
let acceleration =
|
// Pull towards the mouse cursor or touch point
|
||||||
boundary_force + separation_force + alignment_force + cohesion_force + self_force;
|
let attraction_force = pointer.0.map_or(Vec2::ZERO, |target| {
|
||||||
|
(target - transform.translation.xy()).normalize_or_zero()
|
||||||
|
* model_config.attraction_force
|
||||||
|
});
|
||||||
|
|
||||||
|
let acceleration = boundary_force
|
||||||
|
+ separation_force
|
||||||
|
+ alignment_force
|
||||||
|
+ cohesion_force
|
||||||
|
+ self_force
|
||||||
|
+ attraction_force;
|
||||||
boid.velocity += acceleration * dt;
|
boid.velocity += acceleration * dt;
|
||||||
boid.velocity = boid.velocity.clamp_length_max(model_config.max_velocity);
|
boid.velocity = boid.velocity.clamp_length_max(model_config.max_velocity);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ pub struct ModelConfig {
|
||||||
pub cohesion_factor: f32,
|
pub cohesion_factor: f32,
|
||||||
pub separation_factor: f32,
|
pub separation_factor: f32,
|
||||||
pub self_acceleration: f32,
|
pub self_acceleration: f32,
|
||||||
|
pub attraction_force: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ModelConfig {
|
impl Default for ModelConfig {
|
||||||
|
|
@ -36,7 +37,8 @@ impl Default for ModelConfig {
|
||||||
alignment_factor: 0.3,
|
alignment_factor: 0.3,
|
||||||
cohesion_factor: 0.2,
|
cohesion_factor: 0.2,
|
||||||
separation_factor: 500.0,
|
separation_factor: 500.0,
|
||||||
self_acceleration: 30.0,
|
self_acceleration: 100.0,
|
||||||
|
attraction_force: 100.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mod boids;
|
mod boids;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod pointer;
|
||||||
mod spatial_grid;
|
mod spatial_grid;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
|
@ -18,7 +19,12 @@ fn main() {
|
||||||
}),
|
}),
|
||||||
..default()
|
..default()
|
||||||
}))
|
}))
|
||||||
.add_plugins((config::ConfigPlugin, boids::BoidsPlugin, ui::ConfigUiPlugin))
|
.add_plugins((
|
||||||
|
config::ConfigPlugin,
|
||||||
|
pointer::PointerPlugin,
|
||||||
|
boids::BoidsPlugin,
|
||||||
|
ui::ConfigUiPlugin,
|
||||||
|
))
|
||||||
.add_systems(Startup, |mut commands: Commands| {
|
.add_systems(Startup, |mut commands: Commands| {
|
||||||
commands.spawn(Camera2d);
|
commands.spawn(Camera2d);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
28
src/pointer.rs
Normal file
28
src/pointer.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
use bevy::{prelude::*, window::PrimaryWindow};
|
||||||
|
|
||||||
|
pub struct PointerPlugin;
|
||||||
|
|
||||||
|
impl Plugin for PointerPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<PointerTarget>()
|
||||||
|
.add_systems(Update, update_pointer_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// World position of the active touch or mouse cursor, if any.
|
||||||
|
#[derive(Resource, Default)]
|
||||||
|
pub struct PointerTarget(pub Option<Vec2>);
|
||||||
|
|
||||||
|
fn update_pointer_target(
|
||||||
|
window: Single<&Window, With<PrimaryWindow>>,
|
||||||
|
camera: Single<(&Camera, &GlobalTransform)>,
|
||||||
|
touches: Res<Touches>,
|
||||||
|
mut target: ResMut<PointerTarget>,
|
||||||
|
) {
|
||||||
|
let (camera, camera_transform) = *camera;
|
||||||
|
// Touch and cursor positions are both in logical window pixels
|
||||||
|
target.0 = touches
|
||||||
|
.first_pressed_position()
|
||||||
|
.or_else(|| window.cursor_position())
|
||||||
|
.and_then(|position| camera.viewport_to_world_2d(camera_transform, position).ok());
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,7 @@ const CONFIG_FIELDS: &[(&str, f32)] = &[
|
||||||
("cohesion_factor", 0.05),
|
("cohesion_factor", 0.05),
|
||||||
("separation_factor", 10.0),
|
("separation_factor", 10.0),
|
||||||
("self_acceleration", 5.0),
|
("self_acceleration", 5.0),
|
||||||
|
("attraction_force", 10.0),
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue