Skip to content

Commit 4c3ac84

Browse files
committed
multi-quadtree support
1 parent 20f2556 commit 4c3ac84

File tree

8 files changed

+341
-28
lines changed

8 files changed

+341
-28
lines changed

.github/scripts/test.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ statements=(
88
"cargo clippy --no-default-features -- -D warnings"
99
"cargo clippy -F gizmos -- -D warnings"
1010
"cargo clippy -F sprite -- -D warnings"
11-
"cargo clippy -F sprite,gizmos -- -D warnings"
11+
"cargo clippy -F multi-quadtree -- -D warnings"
12+
"cargo clippy --all-features -- -D warnings"
1213

1314
"cargo test --no-default-features"
1415
"cargo test -F gizmos"
15-
"cargo test -F sprite --doc"
16+
"cargo test -F sprite"
17+
"cargo test -F multi-quadtree"
1618
"cargo test --all-features"
1719

1820
"cargo doc --no-deps --all-features"

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com
99
-->
1010

1111
## [Unreleased]
12+
## [0.15.1-alpha11] - 2025-01-23
13+
14+
- multi-quadtree support: see `MultiQuadTreePlugin`
15+
1216
## [0.15.1-alpha10] - 2025-01-23
1317

1418
- fix doc mistakes

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = ["bevy_quadtree"]
33
resolver = "2"
44

55
[workspace.package]
6-
version = "0.15.1-alpha10"
6+
version = "0.15.1-alpha11"
77
authors = ["Louis <[email protected]>"]
88
description = "A quadtree plugin for bevy"
99
license = "MIT"

bevy_quadtree/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ rand_chacha = { version = "0.3.1", default-features = false }
3232
default = []
3333
sprite = ["dep:bevy_sprite"]
3434
gizmos = ["dep:bevy_gizmos", "dep:bevy_color"]
35+
multi-quadtree = []

bevy_quadtree/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Function:
7373
Features:
7474
- `gizmos`: show gizmos of the quadtree boundaries.
7575
- `sprite`: enable `CollisionRect` and `CollisionRotatedRect` to track `sprite.custom_size`.
76+
- `multi-quadtree`: support multiple quadtree in one world.
7677

7778
### Caution
7879

@@ -104,14 +105,14 @@ bevy_quadtree = { version = "0.15.1" }
104105
2. Add the plugin to your Bevy app:
105106

106107
```rust no_run
108+
# #[cfg(feature = "sprite")]
109+
{
107110
# use bevy_app::prelude::*;
108111
# use bevy_transform::prelude::*;
109-
# #[cfg(feature = "sprite")]
110112
# use bevy_sprite::Sprite;
111113
use bevy_quadtree::{QuadTreePlugin, CollisionCircle, CollisionRect};
112114

113115
fn main() {
114-
#[cfg(feature = "sprite")]
115116
App::new()
116117
.add_plugins(QuadTreePlugin::<(
117118
(CollisionCircle, GlobalTransform), (CollisionRect, (GlobalTransform, Sprite)),
@@ -125,6 +126,7 @@ fn main() {
125126
// 20 / 10 = 2 = outlet_boundary / inlet_boundary (for loose quadtree)
126127
.run();
127128
}
129+
# }
128130
```
129131

130132
3. Spawn CollisionShapes as Components:

bevy_quadtree/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ mod system;
1010
pub mod tree;
1111

1212
pub use collision::{Collision, CollisionQuery, Disassemble, UpdateCollision};
13+
#[cfg(feature = "multi-quadtree")]
14+
pub use plugin::{AsQuadTreePluginConfig, MultiQuadTreePlugin, QTConfig, QuadTreePluginConfig};
1315
pub use plugin::{QuadTreePlugin, TrackingPair};
1416
pub use shape::{CollisionCircle, CollisionRect, CollisionRotatedRect};
1517
pub use tree::{All, Contain, Contained, Disjoint, Overlap, QNot, QOr, QRelation, QuadTree};

bevy_quadtree/src/plugin.rs renamed to bevy_quadtree/src/plugin/mod.rs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
//! QuadTree Plugin
2+
//!
3+
4+
#[cfg(feature = "multi-quadtree")]
5+
mod multi_plugin;
6+
7+
#[cfg(feature = "multi-quadtree")]
8+
pub use multi_plugin::{
9+
AsQuadTreePluginConfig, MultiQuadTreePlugin, QTConfig, QuadTreePluginConfig,
10+
};
211

312
use crate::collision::AsDynCollision;
413
use crate::system::{update_collision, update_quadtree};
@@ -9,7 +18,7 @@ use bevy_ecs::prelude::*;
918
use bevy_ecs::schedule::{IntoSystemConfigs, SystemConfigs};
1019
#[cfg(feature = "sprite")]
1120
use bevy_sprite::Sprite;
12-
use bevy_transform::components::GlobalTransform;
21+
use bevy_transform::prelude::*;
1322

1423
/// A Bevy plugin for quadtree.
1524
/// # Type Parameters
@@ -35,34 +44,37 @@ use bevy_transform::components::GlobalTransform;
3544
/// `K`: For `LooseQuadTree`, K / 10 = outlet_boundary / inlet_boundary. Set K to 10 by default and 20 is founded best.
3645
/// K should >= 10. Only if the object move and is **no longer completely contained** by the outlet_boundary will it be inserted again.
3746
///
38-
/// `ID`: If you want different quadtree for different use cases with the same other parameters, set ID to different values.
39-
/// # Panic
40-
/// 1. duplicated shape in `P`.
41-
///
42-
/// e.g. `P = ((CollisionRect, GlobalTransform), (CollisionRect, Sprite))` will lead a debug_assertion failure.
43-
/// Try `P = (CollisionRect, (GlobalTransform, Sprite))` or `P = ((CollisionRect<0>, GlobalTransform), (CollisionRect<1>, Sprite))` in concret context.
44-
///
45-
/// 2. invalid const parameters.
46-
///
47-
/// N, D, W, H should > 0. K should >= 10.
47+
/// `ID`: Set a lucky number as you like for the quadtree.
48+
/// If you want multiple quadtrees, see [`MultiQuadTreePlugin`].
4849
///
4950
/// # Example
5051
/// ```no_run
52+
/// # #[cfg(feature = "sprite")]
53+
/// # {
5154
/// # use bevy_app::prelude::*;
5255
/// # use bevy_transform::prelude::*;
53-
/// # #[cfg(feature = "sprite")]
5456
/// # use bevy_sprite::Sprite;
5557
/// use bevy_quadtree::{CollisionCircle, CollisionRect, CollisionRotatedRect, QuadTreePlugin};
5658
///
57-
/// #[cfg(feature = "sprite")]
5859
/// App::new()
5960
/// .add_plugins(QuadTreePlugin::<(
6061
/// (CollisionCircle, GlobalTransform),
61-
/// (CollisionRotatedRect, GlobalTransform),
62-
/// (CollisionRect, Sprite),
62+
/// (CollisionRotatedRect, Sprite),
63+
/// (CollisionRect, (GlobalTransform, Sprite)),
6364
/// ),
6465
/// 40, 4, 100, 100, 20>::default());
66+
/// # }
6567
/// ```
68+
///
69+
/// # Panic
70+
/// 1. duplicated shapes in `P`. (Debug check only)
71+
///
72+
/// e.g. `P = ((CollisionRect, GlobalTransform), (CollisionRect, Sprite))` will lead a debug_assertion failure.
73+
/// Try `P = (CollisionRect, (GlobalTransform, Sprite))` or `P = ((CollisionRect<0>, GlobalTransform), (CollisionRect<1>, Sprite))` in concret context.
74+
///
75+
/// 2. invalid const parameters. (Debug check only)
76+
///
77+
/// N, D, W, H should > 0. K should >= 10.
6678
#[derive(Debug)]
6779
pub struct QuadTreePlugin<
6880
P,
@@ -200,10 +212,9 @@ macro_rules! impl_tracking_pair_tuple {
200212
impl<S> TrackingPair for (S, ($($c),+,))
201213
where
202214
S: Component + AsDynCollision + $(UpdateCollision<$c>+)+ Clone,
203-
$($c: Component),+,
204-
$((S, $c): TrackingPair),+,
205215
{
206216
fn update_collision() -> SystemConfigs {
217+
// update_collision has Mut<S>, so chain them
207218
($(update_collision::<S, $c>),+,).chain()
208219
}
209220
fn update_quadtree<const N: usize, const D: usize, const W: usize, const H: usize, const K: usize, const ID: usize>(
@@ -240,6 +251,7 @@ macro_rules! impl_tracking_pairs {
240251
$([<P $i>]: TrackingPair),+
241252
{
242253
fn update_collision() -> SystemConfigs {
254+
// no duplicate shape in `P`s, so ambiguous_with_all
243255
($([<P $i>]::update_collision()),+,).ambiguous_with_all()
244256
}
245257
fn update_quadtree<const N: usize, const D: usize, const W: usize, const H: usize, const K: usize, const ID: usize>(
@@ -249,7 +261,7 @@ macro_rules! impl_tracking_pairs {
249261
let mut set = std::collections::HashMap::new();
250262
$(
251263
if let Some(dup) = set.insert([<P $i>]::shape_id(), std::any::type_name::<[<P $i>]>()) {
252-
panic!("Duplicate quadtree updating system added:\n<{}>\n<{}>\nThey have the same collision shape, merge them into one or use `ID` type parameter of shape.", dup, std::any::type_name::<[<P $i>]>());
264+
panic!("Duplicated quadtree updating system added:\n<{}>\n<{}>\nThey have the same collision shape, merge them into one or use `ID` type parameter of shape.", dup, std::any::type_name::<[<P $i>]>());
253265
}
254266
);+
255267
}
@@ -263,15 +275,15 @@ macro_rules! impl_tracking_pairs {
263275
let mut set = std::collections::HashMap::new();
264276
$(
265277
if let Some(dup) = set.insert([<P $i>]::shape_id(), std::any::type_name::<[<P $i>]>()) {
266-
panic!("Duplicate gizmos box updating system added:\n<{}>\n<{}>\nThey have the same collision shape, merge them into one or use `ID` type parameter of shape.", dup, std::any::type_name::<[<P $i>]>());
278+
panic!("Duplicated gizmos box updating system added:\n<{}>\n<{}>\nThey have the same collision shape, merge them into one or use `ID` type parameter of shape.", dup, std::any::type_name::<[<P $i>]>());
267279
}
268280
);+
269281
}
270282
($([<P $i>]::show_boundary::<N, D, W, H, K, ID>()),+,).ambiguous_with_all()
271283
}
272284
#[cfg(debug_assertions)]
273285
fn shape_id() -> std::any::TypeId {
274-
unreachable!()
286+
unreachable!("only (S, C) and ((S1, C), (S2, C), ...) are allowed")
275287
}
276288
}
277289
}
@@ -295,7 +307,7 @@ mod tests {
295307
use crate::{CollisionCircle, CollisionRect, CollisionRotatedRect};
296308

297309
#[test]
298-
#[should_panic(expected = "Duplicate quadtree updating system added")]
310+
#[should_panic(expected = "Duplicated quadtree updating system added")]
299311
fn duplicate_shape1() {
300312
App::new().add_plugins(QuadTreePlugin::<
301313
(
@@ -312,7 +324,7 @@ mod tests {
312324

313325
#[cfg(feature = "sprite")]
314326
#[test]
315-
#[should_panic(expected = "Duplicate quadtree updating system added")]
327+
#[should_panic(expected = "Duplicated quadtree updating system added")]
316328
fn duplicate_shape2() {
317329
App::new().add_plugins(QuadTreePlugin::<
318330
((CollisionRect, GlobalTransform), (CollisionRect, Sprite)),
@@ -326,7 +338,7 @@ mod tests {
326338

327339
#[cfg(feature = "sprite")]
328340
#[test]
329-
#[should_panic(expected = "Duplicate quadtree updating system added")]
341+
#[should_panic(expected = "Duplicated quadtree updating system added")]
330342
fn duplicate_shape3() {
331343
App::new().add_plugins(QuadTreePlugin::<
332344
(
@@ -374,4 +386,20 @@ mod tests {
374386
20,
375387
>::default());
376388
}
389+
390+
#[cfg(feature = "sprite")]
391+
#[test]
392+
fn plugin_test_tuple() {
393+
App::new().add_plugins(QuadTreePlugin::<
394+
(
395+
(CollisionRect<0>, (GlobalTransform, Sprite)),
396+
(CollisionRect<1>, GlobalTransform),
397+
),
398+
40,
399+
4,
400+
100,
401+
100,
402+
20,
403+
>::default());
404+
}
377405
}

0 commit comments

Comments
 (0)