167 lines
4.6 KiB
Rust
167 lines
4.6 KiB
Rust
use std::ops::Deref;
|
|
use std::time::Duration;
|
|
|
|
use bevy::{
|
|
color::palettes::css as csscolors,
|
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
|
math::Vec3Swizzles,
|
|
prelude::*,
|
|
window::PrimaryWindow,
|
|
};
|
|
use bevy_spatial::{AutomaticUpdate, SpatialStructure};
|
|
use bevy_spatial::{SpatialAccess, kdtree::KDTree2};
|
|
// marker for entities tracked by the KDTree
|
|
#[derive(Component, Default)]
|
|
struct NearestNeighbourComponent;
|
|
|
|
// marker for the "cursor" entity
|
|
#[derive(Component)]
|
|
struct Cursor;
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins.set(WindowPlugin {
|
|
primary_window: Some(Window {
|
|
present_mode: bevy::window::PresentMode::AutoNoVsync,
|
|
..default()
|
|
}),
|
|
..default()
|
|
}))
|
|
// Add the plugin, which takes the tracked component as a generic.
|
|
.add_plugins(
|
|
AutomaticUpdate::<NearestNeighbourComponent>::new()
|
|
.with_spatial_ds(SpatialStructure::KDTree2)
|
|
.with_frequency(Duration::from_millis(1)),
|
|
)
|
|
.add_plugins(LogDiagnosticsPlugin::default())
|
|
.add_plugins(FrameTimeDiagnosticsPlugin::default())
|
|
.insert_resource(Mouse2D { pos: Vec2::ZERO })
|
|
.add_systems(Startup, setup)
|
|
.add_systems(
|
|
Update,
|
|
(
|
|
update_mouse_pos,
|
|
(
|
|
mouse,
|
|
color,
|
|
reset_color.before(color),
|
|
collide_wall,
|
|
movement,
|
|
),
|
|
)
|
|
.chain(),
|
|
)
|
|
.run();
|
|
}
|
|
|
|
// type alias for easier usage later
|
|
type NNTree = KDTree2<NearestNeighbourComponent>;
|
|
|
|
fn setup(mut commands: Commands) {
|
|
commands.spawn(Camera2d);
|
|
commands.spawn((
|
|
Cursor,
|
|
Sprite {
|
|
color: Color::srgb(0.0, 0.0, 1.0),
|
|
custom_size: Some(Vec2::new(10.0, 10.0)),
|
|
..default()
|
|
},
|
|
Transform {
|
|
translation: Vec3::ZERO,
|
|
..default()
|
|
},
|
|
));
|
|
let sprite = Sprite {
|
|
color: csscolors::ORANGE_RED.into(),
|
|
custom_size: Some(Vec2::new(6.0, 6.0)),
|
|
..default()
|
|
};
|
|
for x in -100..100 {
|
|
for y in -100..100 {
|
|
commands.spawn((
|
|
NearestNeighbourComponent,
|
|
sprite.clone(),
|
|
Transform {
|
|
translation: Vec3::new((x * 4) as f32, (y * 4) as f32, 0.0),
|
|
..default()
|
|
},
|
|
));
|
|
}
|
|
}
|
|
}
|
|
#[derive(Copy, Clone, Resource)]
|
|
struct Mouse2D {
|
|
pos: Vec2,
|
|
}
|
|
|
|
fn update_mouse_pos(
|
|
window: Single<&Window, With<PrimaryWindow>>,
|
|
camera: Single<(&Camera, &GlobalTransform)>,
|
|
mut mouse: ResMut<Mouse2D>,
|
|
) {
|
|
let (cam, cam_t) = camera.deref();
|
|
if let Some(w_pos) = window.cursor_position() {
|
|
if let Ok(pos) = cam.viewport_to_world_2d(cam_t, w_pos) {
|
|
mouse.pos = pos;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn mouse(
|
|
mut commands: Commands,
|
|
mouse: Res<Mouse2D>,
|
|
treeaccess: Res<NNTree>,
|
|
mut transform: Single<&mut Transform, With<Cursor>>,
|
|
ms_buttons: Res<ButtonInput<MouseButton>>,
|
|
) {
|
|
let use_mouse = ms_buttons.pressed(MouseButton::Left);
|
|
|
|
if let Some((_pos, entity)) = treeaccess.nearest_neighbour(mouse.pos) {
|
|
transform.translation = mouse.pos.extend(0.0); // I don't really know what this is here for
|
|
|
|
if use_mouse {
|
|
commands.entity(entity.unwrap()).despawn();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn color(
|
|
treeaccess: Res<NNTree>,
|
|
mouse: Res<Mouse2D>,
|
|
mut query: Query<&mut Sprite, With<NearestNeighbourComponent>>,
|
|
) {
|
|
for (_, entity) in treeaccess.within_distance(mouse.pos, 50.0) {
|
|
if let Ok(mut sprite) = query.get_mut(entity.unwrap()) {
|
|
sprite.color = Color::BLACK;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn reset_color(mut query: Query<&mut Sprite, With<NearestNeighbourComponent>>) {
|
|
for mut sprite in &mut query {
|
|
sprite.color = csscolors::ORANGE_RED.into();
|
|
}
|
|
}
|
|
|
|
fn movement(mut query: Query<&mut Transform, With<NearestNeighbourComponent>>) {
|
|
for mut pos in &mut query {
|
|
let goal = pos.translation - Vec3::ZERO;
|
|
pos.translation += goal.normalize_or_zero();
|
|
}
|
|
}
|
|
|
|
fn collide_wall(
|
|
window: Single<&Window, With<PrimaryWindow>>,
|
|
mut query: Query<&mut Transform, With<NearestNeighbourComponent>>,
|
|
) {
|
|
let w = window.width() / 2.0;
|
|
let h = window.height() / 2.0;
|
|
|
|
for mut pos in &mut query {
|
|
let [x, y] = pos.translation.xy().to_array();
|
|
if y < -h || x < -w || y > h || x > w {
|
|
pos.translation = pos.translation.normalize_or_zero();
|
|
}
|
|
}
|
|
}
|