Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ readme = "README.md"
authors = ["laund <me@laund.moe>"]

[dependencies]
bevy = { version = "0.16", default-features = false }
bevy = { version = "0.19", default-features = false }
# KD-Tree dependencies
kd-tree = { version = "0.6.0", optional = true }
typenum = { version = "1.18.0" }
Expand All @@ -23,7 +23,7 @@ kdtree_rayon = ["kdtree", "kd-tree/rayon"]
kdtree = ["dep:kd-tree"]

[dev-dependencies]
bevy = { version = "0.16" }
bevy = { version = "0.19" }
rand = "0.8"

[profile.dev]
Expand Down
8 changes: 5 additions & 3 deletions examples/distance3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut ambient_light: ResMut<AmbientLight>,
) {
let handles = MaterialHandles {
orange_red: materials.add(Color::from(csscolors::ORANGE_RED)),
Expand All @@ -50,8 +49,11 @@ fn setup(
};
commands.insert_resource(handles.clone());

ambient_light.color = Color::WHITE;
ambient_light.brightness = 500.;
commands.insert_resource(GlobalAmbientLight {
color: Color::WHITE,
brightness: 500.,
..default()
});

commands.spawn((
Camera3d::default(),
Expand Down
2 changes: 1 addition & 1 deletion examples/modify_timestep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn setup(mut commands: Commands) {
commands.spawn((
Text("Click mouse to change rate".to_string()),
TextFont {
font_size: 30.0,
font_size: FontSize::Px(30.0),
..default()
},
TextColor(Color::BLACK),
Expand Down
171 changes: 171 additions & 0 deletions examples/within2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
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, SpatialAABBAccess, 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_rect,
reset_color.before(color_rect),
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>,
ms_buttons: Res<ButtonInput<MouseButton>>,
mut query: Query<&mut Sprite, With<NearestNeighbourComponent>>,
) {
let use_mouse = ms_buttons.pressed(MouseButton::Left);

let p1 = mouse.pos;
let p2 = Vec2::from([100.0, -100.0]);

for (_, entity) in treeaccess.within(p1, p2) {
if use_mouse {
commands.entity(entity.unwrap()).despawn();
}

}
}

fn color_rect(
treeaccess: Res<NNTree>,
mouse: Res<Mouse2D>,
mut query: Query<&mut Sprite, With<NearestNeighbourComponent>>,
) {
let p1 = mouse.pos;
let p2 = Vec2::from([100.0, -100.0]);

for (_, entity) in treeaccess.within(p1, p2) {
if let Ok(mut sprite) = query.get_mut(entity.unwrap()) {
sprite.color = csscolors::GREEN.into();
}
}
}

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();
}
}
}
9 changes: 6 additions & 3 deletions src/automatic_systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use crate::{
};

use bevy::{
ecs::schedule::{ScheduleLabel, SystemSet},
ecs::{
component::Mutable,
schedule::{ScheduleLabel, SystemSet},
},
prelude::*,
};

Expand All @@ -29,7 +32,7 @@ pub(crate) struct AutoT<SpatialDS>(PhantomData<SpatialDS>);
impl<SpatialDS> AutoT<SpatialDS>
where
GlamVec<SpatialDS>: VecFromTransform,
SpatialDS: UpdateSpatialAccess + Resource,
SpatialDS: UpdateSpatialAccess + Resource<Mutability = Mutable>,
<SpatialDS as SpatialAccess>::Point: From<(Entity, GlamVec<SpatialDS>)>,
SpatialDS::Comp: Component,
{
Expand Down Expand Up @@ -61,7 +64,7 @@ pub(crate) struct AutoGT<SpatialDS>(PhantomData<SpatialDS>);
impl<SpatialDS> AutoGT<SpatialDS>
where
GlamVec<SpatialDS>: VecFromGlobalTransform,
SpatialDS: UpdateSpatialAccess + Resource,
SpatialDS: UpdateSpatialAccess + Resource<Mutability = Mutable>,
<SpatialDS as SpatialAccess>::Point: From<(Entity, GlamVec<SpatialDS>)>,
SpatialDS::Comp: Component,
{
Expand Down
31 changes: 30 additions & 1 deletion src/kdtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use kd_tree::{KdPoint, KdTree as BaseKdTree, KdTreeN};
use crate::{
TComp,
point::SpatialPoint,
spatial_access::{SpatialAccess, UpdateSpatialAccess},
spatial_access::{SpatialAABBAccess, SpatialAccess, UpdateSpatialAccess},
};

use std::marker::PhantomData;
Expand Down Expand Up @@ -47,6 +47,35 @@ macro_rules! kdtree_impl {
}
}

impl<Comp> SpatialAABBAccess for $treename<Comp>
where
Comp: TComp,
{
/// Return all points which are within the specified rectangular axis-aligned region.
fn within(
&self,
loc1: <Self::Point as SpatialPoint>::Vec,
loc2: <Self::Point as SpatialPoint>::Vec,
) -> Vec<Self::ResultT> {
let _span = info_span!("within").entered();

let p1: $pt = loc1.min(loc2).into();
let p2: $pt = loc1.max(loc2).into();

let rect = [p1, p2];

if self.tree.len() == 0 {
vec![]
} else {
self.tree
.within(&rect)
.iter()
.map(|e| (e.vec(), e.entity()))
.collect()
}
}
}

impl<Comp> SpatialAccess for $treename<Comp>
where
Comp: TComp,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

pub mod point;
mod spatial_access;
pub use self::spatial_access::SpatialAccess;
pub use self::spatial_access::{SpatialAccess, SpatialAABBAccess};

use bevy::prelude::Component;
mod timestep;
Expand Down
9 changes: 8 additions & 1 deletion src/spatial_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,11 @@ pub trait SpatialAccess: Send + Sync + 'static {
) -> Vec<Self::ResultT>;
}

// TODO: SpatialAABBAccess trait definition - should it be separate from SpatialAccess or depend on it?
pub trait SpatialAABBAccess: SpatialAccess {
/// Return all points which are within the specified rectangular axis-aligned region.
fn within(
&self,
loc1: <Self::Point as SpatialPoint>::Vec,
loc2: <Self::Point as SpatialPoint>::Vec,
) -> Vec<Self::ResultT>;
}