diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 0000000..050dff4 --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,7 @@ +[profile.ci] +fail-fast = false + +[profile.ci.junit] +path = "junit.xml" +store-success-output = true +store-failure-output = true \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..52e82a9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,64 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + branches: [ "master", "dev" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + checks: + name: Lints + runs-on: ubuntu-22.04 + steps: + - uses: olix0r/cargo-action-fmt/setup@v2 + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - name: Run cargo fmt + run: cargo fmt --all -- --check + - name: Run cargo check + if: always() + run: cargo check --lib --all-features --message-format json | cargo-action-fmt + - name: Run cargo clippy + if: always() + run: cargo clippy --all-features --no-deps --message-format json -- -D warnings | cargo-action-fmt + + tests: + name: Test Suite + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + backend: + - feature: parry3d + artifact_key: benches + test_arg: --benches + - feature: parry3d + artifact_key: parry3d + test_arg: --test parry3d + - feature: avian + artifact_key: avian + test_arg: --test avian + - feature: rapier + artifact_key: rapier3d + test_arg: --test rapier3d + steps: + - name: Checkout repository code. + uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.backend.artifact_key }} + - name: Install alsalib headers + run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev + - uses: taiki-e/install-action@nextest + - name: Test with nextest + run: cargo nextest run --no-default-features --features "${{ matrix.backend.feature }}" ${{ matrix.backend.test_arg }} --profile ci + - name: Upload Test Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: junit-test-results-${{ matrix.backend.artifact_key }} + path: target/nextest/**/*.xml + retention-days: 1 diff --git a/.github/workflows/test_avian.yml b/.github/workflows/test_avian.yml deleted file mode 100644 index 44cb29f..0000000 --- a/.github/workflows/test_avian.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Test Avian - -on: - push: - pull_request: - branches: [ "master", "dev" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Checkout repository code. - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - name: Install alsalib headers - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - - name: Run tests for repository. - run: cargo test --no-default-features --features "avian" diff --git a/.github/workflows/test_parry.yml b/.github/workflows/test_parry.yml deleted file mode 100644 index 8279148..0000000 --- a/.github/workflows/test_parry.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Test Parry3d - -on: - push: - pull_request: - branches: [ "master", "dev" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Checkout repository code. - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - name: Install alsalib headers - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - - name: Run tests for repository. - run: cargo test --features "parry_016" diff --git a/.github/workflows/test_rapier.yml b/.github/workflows/test_rapier.yml deleted file mode 100644 index 238b714..0000000 --- a/.github/workflows/test_rapier.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Test Rapier - -on: - push: - pull_request: - branches: [ "master", "dev" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Checkout repository code. - uses: actions/checkout@v3 - - uses: Swatinem/rust-cache@v2 - - name: Install alsalib headers - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev - - name: Run tests for repository. - run: cargo test --features "rapier" diff --git a/.gitignore b/.gitignore index 4fffb2f..8eb581d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /Cargo.lock +/.idea diff --git a/Cargo.toml b/Cargo.toml index 3fcadf3..d730092 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,69 +14,72 @@ documentation = "https://docs.rs/crate/oxidized_navigation" keywords = ["gamedev", "navmesh", "navmesh-generation", "bevy"] categories = ["game-development"] +[lib] +bench = false + [features] -default = ["parry_016"] -rapier = ["bevy_rapier3d", "parry_016"] -avian = ["avian3d", "parry_015"] -debug_draw = ["bevy/bevy_gizmos", "bevy/bevy_render"] +default = ["parry3d"] +rapier = ["bevy_rapier3d", "parry3d"] +avian = ["avian3d", "parry3d"] +debug_draw = ["bevy/bevy_gizmos", "bevy/bevy_render", "bevy_rapier3d?/debug-render-3d", "avian3d?/debug-plugin"] trace = [] -parry_016 = ["parry3d_016"] -parry_015 = ["parry3d_015"] - [[example]] name = "rapier3d" -required-features = ["debug_draw", "rapier"] +required-features = ["rapier", "debug_draw"] [[example]] name = "rapier3d_heightfield" -required-features = ["debug_draw", "rapier"] +required-features = ["rapier", "debug_draw"] [[example]] name = "rapier3d_multi_floor" -required-features = ["debug_draw", "rapier"] +required-features = ["rapier", "debug_draw"] [[example]] name = "avian" -required-features = ["debug_draw", "avian"] +required-features = ["avian", "debug_draw"] + +[[example]] +name = "avian_multi_floor" +required-features = ["avian", "debug_draw"] [[example]] name = "parry3d" -required-features = ["parry_016", "debug_draw"] +required-features = ["parry3d", "debug_draw"] [[test]] name = "rapier3d" required-features = ["rapier"] - [[test]] name = "avian" required-features = ["avian"] [[test]] name = "parry3d" -required-features = ["parry_016"] +required-features = ["parry3d"] [dependencies] -bevy = { version = "0.14", default-features = false, features = ["multi_threaded"] } +bevy = { version = "0.15", default-features = false, features = ["multi_threaded"] } # parry3d doesn't expose the convert-glam feature, so we need to add nalgebra to enable the feature -nalgebra = { version = "0.33", features = ["convert-glam027"] } +nalgebra = { version = "0.33", features = ["convert-glam029"] } -parry3d_016 = { package = "parry3d", version = "0.16", optional = true } -parry3d_015 = { package = "parry3d", version = "0.15", optional = true } +parry3d = { version = "0.17", optional = true } -bevy_rapier3d = { version = "0.27", optional = true, default-features = false, features = ["dim3"] } -avian3d = { version = "0.1", optional = true, default-features = false, features = ["3d", "f32", "parry-f32"] } +bevy_rapier3d = { version = "0.28", optional = true, default-features = false, features = ["dim3"] } +avian3d = { version = "0.1", optional = true, default-features = false, features = ["3d", "f32", "parry-f32"] } smallvec = { version = "1.13", features = ["union"] } -cfg-if = "1.0.0" +cfg-if = "1.0" [dev-dependencies] -bevy = { version = "0.14.0", default-features = false, features = [ +bevy = { version = "0.15", default-features = false, features = [ "bevy_asset", "bevy_pbr", "bevy_render", + "bevy_window", "bevy_winit", "x11", "ktx2", @@ -88,13 +91,16 @@ criterion = { version = "0.5" } [[bench]] name = "simple_geometry" harness = false -required-features = [ "parry_016" ] +required-features = ["parry3d"] [[bench]] name = "simple_navigation" harness = false -required-features = [ "parry_016" ] +required-features = ["parry3d"] [package.metadata.docs.rs] # Compile docs.rs docs with debug_draw so docs for it appear. -features = [ "debug_draw" ] +features = ["debug_draw"] + +[patch.crates-io] +avian3d = { git = "https://github.com/Jondolf/avian.git", rev = "52cbcec" } \ No newline at end of file diff --git a/MIGRATING.md b/MIGRATING.md index b7a82ae..8dc6c5d 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -1,3 +1,38 @@ +## 0.12.0 + +### Minimum `bevy` version is `0.15.0` + +### Replaced `Xpbd` support with its replacement `Avian3d` + +See [Rebrand Bevy XPBD](https://github.com/Jondolf/avian/issues/346). + +Currently `Avian3D` has yet to publish an official `bevy:0.15` release, so you will need to use a crates-io patch to use this backend: + +```toml +[dependencies] +avian3d = { version = "0.1" } +oxidized_navigation = { version = "0.12.0", features = ["avian"] } + +[patch.crates-io] +avian3d = { git = "https://github.com/Jondolf/avian.git", rev = "52cbcec" } +``` + +### Removed `parry_` features + +If you were depending on the `parry_015` / `parry_016` features these have been replaced with a single `parry3d` feature that currently adds a dependency on `parry3d:0.17`: + +```toml +# 0.11: +[dependencies] +parry3d = { version = "0.16" } +oxidized_navigation = { version = "0.11.0", features = ["parry_016"] } + +# 0.12: +[dependencies] +parry3d = { version = "0.17" } +oxidized_navigation = { version = "0.12.0", features = ["parry3d"] } +``` + ## 0.7 ### ``OxidizedNavigationPlugin`` is now generic over OxidizedColliders. diff --git a/README.md b/README.md index 5c1b19d..d9e65c8 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Takes in [Parry3d](https://crates.io/crates/parry3d) colliders that implement th ## Quick-start: **Nav-mesh generation:** -1. Choose which backend you're going to use (bevy_rapier3d, avian_3d, or custom parry3d based colliders) and enable the relevant crate features ("rapier", "avian", or "parry_016" features). +1. Choose which backend you're going to use (bevy_rapier3d, avian_3d, or custom parry3d based colliders) and enable the relevant crate features (`rapier`, `avian`, or `parry3d` features). 2. If you opted for custom parry3d colliders, implement the `OxidizedCollider` trait for your collider component that wraps a `parry3d::shape::SharedShape`. This is already done for `bevy_rapier3d` and `avian_3d`. 3. Add ``OxidizedNavigationPlugin`` as a plugin. (eg. for avian `OxidizedNavigationPlugin::::new(NavMeshSettings {...}`) 4. Attach a ``NavMeshAffector`` component and a collider that implements the `OxidizedCollider` trait (already implemented for `bevy_rapier3d` and `avian_3d`) to any entity you want to affect the nav-mesh. @@ -57,21 +57,28 @@ Debug draw is available behind the ``debug_draw`` feature and using the ``Oxidiz ## Supported versions -| Crate Version | Bevy Version | Bevy Rapier 3D Version | Bevy Xpbd 3D Version | Parry3d Version | -| ------------- | ------------ | ---------------------- | -------------------- | --------------- | -| 0.11.0 | 0.14 | 0.27 | 0.5 | 0.15/0.16 | -| 0.10.0 | 0.13 | 0.25 | 0.4 | 0.13 | -| 0.9.0 | 0.12 | 0.24 | 0.3 | 0.13 | -| 0.8.0 | 0.12 | 0.23 | 0.3 | 0.13 | -| 0.7.0 | 0.11 | 0.22 | 0.2 | 0.13 | -| 0.6.0 | 0.11 | 0.22 | unsupported | unsupported | -| 0.5.X | 0.10.X | 0.21 | unsupported | unsupported | -| 0.4.0 | 0.10.X | 0.21 | unsupported | unsupported | -| 0.3.0 | 0.10.0 | 0.21 | unsupported | unsupported | -| 0.2.0 | 0.9.X | 0.20 | unsupported | unsupported | -| 0.1.X | 0.9.X | 0.19 | unsupported | unsupported | - -**Using an unsupported Rapier, Xpbd, or parry3d version will cause Oxidized Navigation to fail as it tries to get the wrong version of components.** +| Crate Version | Bevy Version | Bevy Rapier 3D Version | Bevy Xpbd 3D Version | Avian3D Version | Parry3d Version | +|---------------|--------------|------------------------|----------------------|---------------------|-----------------| +| 0.12.0 | 0.15 | 0.28 | unsupported | git-rev-52cbcec (1) | 0.17 | +| 0.11.0 | 0.14 | 0.27 | 0.5 | unsupported | 0.15/0.16 | +| 0.9.0 | 0.12 | 0.24 | 0.3 | unsupported | 0.13 | +| 0.10.0 | 0.13 | 0.25 | 0.4 | unsupported | 0.13 | +| 0.8.0 | 0.12 | 0.23 | 0.3 | unsupported | 0.13 | +| 0.7.0 | 0.11 | 0.22 | 0.2 | unsupported | 0.13 | +| 0.6.0 | 0.11 | 0.22 | unsupported | unsupported | unsupported | +| 0.5.X | 0.10.X | 0.21 | unsupported | unsupported | unsupported | +| 0.4.0 | 0.10.X | 0.21 | unsupported | unsupported | unsupported | +| 0.3.0 | 0.10.0 | 0.21 | unsupported | unsupported | unsupported | +| 0.2.0 | 0.9.X | 0.20 | unsupported | unsupported | unsupported | +| 0.1.X | 0.9.X | 0.19 | unsupported | unsupported | unsupported | + +### (1) +- Avian3D has yet to publish an official bevy-0.15 release. There will be a 0.12.1 release when they do +- You will need to use a `[patch.crates-io]` override for now see [MIGRATING - 0.12.0](https://github.com/TheGrimsey/oxidized_navigation/blob/master/MIGRATING.md#0120) +- The minimum git rev sha supported is [52cbcec](https://github.com/Jondolf/avian/commit/52cbcecce0fd05a65005ab6935ebeb231373c2c6) +- Newer git revs will possibly (probably) work but are untested with this crate, YMMV 🤷🏼 + +**Using an unsupported Rapier, Xpbd, Avian3d or parry3d version will cause Oxidized Navigation to fail as it tries to get the wrong version of components.** In this case you may be able to [override which version Oxidized Navigation depends on](https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html). ## Non-exhaustive TODO-list: diff --git a/examples/avian.rs b/examples/avian.rs index 85a557e..e8220f4 100644 --- a/examples/avian.rs +++ b/examples/avian.rs @@ -1,7 +1,9 @@ //! A simple example showing how to use oxidized_navigation with Avian3d. +//! Press M to draw nav-mesh. +//! Press X to spawn or despawn red cube. -use bevy::{math::primitives, prelude::*}; use avian3d::prelude::{Collider, PhysicsPlugins}; +use bevy::{math::primitives, prelude::*}; use oxidized_navigation::{ debug_draw::{DrawNavMesh, OxidizedNavigationDebugDrawPlugin}, NavMeshAffector, NavMeshSettings, OxidizedNavigationPlugin, @@ -27,16 +29,15 @@ fn main() { .add_systems(Startup, setup) .add_systems( Update, - (toggle_nav_mesh_system, spawn_or_despawn_affector_system), + (toggle_nav_mesh_debug_draw, spawn_or_despawn_affector_system), ) .run(); } -// -// Toggle drawing Nav-mesh. -// Press M to toggle drawing the navmesh. -// -fn toggle_nav_mesh_system(keys: Res>, mut show_navmesh: ResMut) { +fn toggle_nav_mesh_debug_draw( + keys: Res>, + mut show_navmesh: ResMut, +) { if keys.just_pressed(KeyCode::KeyM) { show_navmesh.0 = !show_navmesh.0; } @@ -49,53 +50,44 @@ fn setup( ) { print_controls(); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(10.0, 10.0, 15.0) - .looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), - ..default() - }); + // Camera + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(10.0, 10.0, 15.0).looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), + )); - commands.spawn(DirectionalLightBundle { - directional_light: DirectionalLight { + // Directional light + commands.spawn(( + DirectionalLight { shadows_enabled: true, ..default() }, - transform: Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), - ..default() - }); + Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), + )); - // Plane + // Ground plane commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Rectangle::from_size(Vec2::new(50.0, 50.0))), - material: materials.add(Color::srgb(0.3, 0.5, 0.3)), - transform: Transform::IDENTITY, - ..default() - }, + Mesh3d(meshes.add(Plane3d::default().mesh().size(25.0, 25.0))), + MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), + Transform::IDENTITY, Collider::cuboid(25.0, 0.1, 25.0), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); // Cube commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5)), - material: materials.add(Color::srgb(0.1, 0.1, 0.5)), - transform: Transform::from_xyz(-5.0, 0.8, -5.0), - ..default() - }, + Mesh3d(meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5))), + MeshMaterial3d(materials.add(Color::srgb(0.1, 0.1, 0.5))), + Transform::from_xyz(-5.0, 0.8, -5.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); // Thin wall commands.spawn(( - PbrBundle { - mesh: meshes.add(Mesh::from(primitives::Cuboid::new(0.1, 0.1, 0.1))), - material: materials.add(Color::srgb(0.1, 0.1, 0.5)), - transform: Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), - ..default() - }, + Mesh3d(meshes.add(Mesh::from(primitives::Cuboid::new(0.1, 0.1, 0.1)))), + MeshMaterial3d(materials.add(Color::srgb(0.1, 0.1, 0.5))), + Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), Collider::cuboid(0.05, 0.05, 0.05), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); @@ -118,12 +110,9 @@ fn spawn_or_despawn_affector_system( } else { let entity = commands .spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5)), - material: materials.add(Color::srgb(1.0, 0.1, 0.5)), - transform: Transform::from_xyz(5.0, 0.8, 0.0), - ..default() - }, + Mesh3d(meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5))), + MeshMaterial3d(materials.add(Color::srgb(1.0, 0.1, 0.5))), + Transform::from_xyz(5.0, 0.8, 0.0), Collider::cuboid(2.5, 2.5, 2.5), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )) diff --git a/examples/avian_multi_floor.rs b/examples/avian_multi_floor.rs new file mode 100644 index 0000000..519257a --- /dev/null +++ b/examples/avian_multi_floor.rs @@ -0,0 +1,279 @@ +//! Nav-mesh set up example for multiple floors. +//! +//! Press A to run async path finding. +//! +//! Press B to run blocking path finding. +//! + +use avian3d::prelude::Collider; +use avian3d::PhysicsPlugins; +use bevy::tasks::futures_lite::future; +use bevy::{ + color::palettes, + math::primitives, + prelude::*, + tasks::{AsyncComputeTaskPool, Task}, +}; +use oxidized_navigation::{ + debug_draw::{DrawNavMesh, DrawPath, OxidizedNavigationDebugDrawPlugin}, + query::{find_path, find_polygon_path, perform_string_pulling_on_path}, + tiles::NavMeshTiles, + NavMesh, NavMeshAffector, NavMeshSettings, OxidizedNavigationPlugin, +}; +use std::sync::{Arc, RwLock}; + +fn main() { + App::new() + // Default Plugins + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + title: "Oxidized Navigation: Rapier 3d Multi floor".to_owned(), + ..default() + }), + ..default() + }), + OxidizedNavigationPlugin::::new(NavMeshSettings::from_agent_and_bounds( + 0.5, 1.9, 250.0, -1.0, + )), + OxidizedNavigationDebugDrawPlugin, + // The rapier plugin needs to be added for the scales of colliders to be correct if the scale of the entity is not uniformly 1. + // An example of this is the "Thin Wall" in [setup_world_system]. If you remove this plugin, it will not appear correctly. + PhysicsPlugins::default(), + )) + .insert_resource(AsyncPathfindingTasks::default()) + .add_systems(Startup, setup_world_system) + .add_systems( + Update, + ( + run_blocking_pathfinding, + run_async_pathfinding, + poll_pathfinding_tasks_system, + toggle_nav_mesh_debug_draw, + spawn_or_despawn_affector_system, + ), + ) + .run(); +} + +fn run_blocking_pathfinding( + mut commands: Commands, + keys: Res>, + nav_mesh_settings: Res, + nav_mesh: Res, +) { + if !keys.just_pressed(KeyCode::KeyB) { + return; + } + + // Get the underlying nav_mesh. + if let Ok(nav_mesh) = nav_mesh.get().read() { + let start_pos = Vec3::new(5.0, 1.0, 5.0); + let end_pos = Vec3::new(-15.0, 1.0, -15.0); + + // Run pathfinding to get a polygon path. + match find_polygon_path( + &nav_mesh, + &nav_mesh_settings, + start_pos, + end_pos, + None, + Some(&[1.0, 0.5]), + ) { + Ok(path) => { + info!("Path found (BLOCKING): {:?}", path); + + // Convert polygon path to a path of Vec3s. + match perform_string_pulling_on_path(&nav_mesh, start_pos, end_pos, &path) { + Ok(string_path) => { + info!("String path (BLOCKING): {:?}", string_path); + commands.spawn(DrawPath { + timer: Some(Timer::from_seconds(4.0, TimerMode::Once)), + pulled_path: string_path, + color: palettes::css::RED.into(), + }); + } + Err(error) => error!("Error with string path: {:?}", error), + }; + } + Err(error) => error!("Error with pathfinding: {:?}", error), + } + } +} + +// Running pathfinding in a task without blocking the frame. +// Also check out Bevy's async compute example. +// https://github.com/bevyengine/bevy/blob/main/examples/async_tasks/async_compute.rs + +// Holder resource for tasks. +#[derive(Default, Resource)] +struct AsyncPathfindingTasks { + tasks: Vec>>>, +} + +// Queue up pathfinding tasks. +fn run_async_pathfinding( + keys: Res>, + nav_mesh_settings: Res, + nav_mesh: Res, + mut pathfinding_task: ResMut, +) { + if !keys.just_pressed(KeyCode::KeyA) { + return; + } + + let thread_pool = AsyncComputeTaskPool::get(); + + let nav_mesh_lock = nav_mesh.get(); + let start_pos = Vec3::new(5.0, 1.0, 5.0); + let end_pos = Vec3::new(-15.0, 1.0, -15.0); + + let task = thread_pool.spawn(async_path_find( + nav_mesh_lock, + nav_mesh_settings.clone(), + start_pos, + end_pos, + None, + )); + + pathfinding_task.tasks.push(task); +} + +// Poll existing tasks. +fn poll_pathfinding_tasks_system( + mut commands: Commands, + mut pathfinding_task: ResMut, +) { + // Go through and remove completed tasks. + pathfinding_task.tasks.retain_mut(|task| { + if let Some(string_path) = future::block_on(future::poll_once(task)).unwrap_or(None) { + info!("Async path task finished with result: {:?}", string_path); + commands.spawn(DrawPath { + timer: Some(Timer::from_seconds(4.0, TimerMode::Once)), + pulled_path: string_path, + color: palettes::css::BLUE.into(), + }); + + false + } else { + true + } + }); +} + +/// Async wrapper function for path finding. +async fn async_path_find( + nav_mesh_lock: Arc>, + nav_mesh_settings: NavMeshSettings, + start_pos: Vec3, + end_pos: Vec3, + position_search_radius: Option, +) -> Option> { + // Get the underlying nav_mesh. + let Ok(nav_mesh) = nav_mesh_lock.read() else { + return None; + }; + + // Run pathfinding to get a path. + match find_path( + &nav_mesh, + &nav_mesh_settings, + start_pos, + end_pos, + position_search_radius, + Some(&[1.0, 0.5]), + ) { + Ok(path) => { + info!("Found path (ASYNC): {:?}", path); + return Some(path); + } + Err(error) => error!("Error with pathfinding: {:?}", error), + } + + None +} + +fn toggle_nav_mesh_debug_draw( + keys: Res>, + mut show_navmesh: ResMut, +) { + if keys.just_pressed(KeyCode::KeyM) { + show_navmesh.0 = !show_navmesh.0; + } +} + +fn setup_world_system( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + print_controls(); + + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(15.0, 10.0, 20.0).looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), + )); + + commands.spawn(( + DirectionalLight { + shadows_enabled: true, + ..default() + }, + Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), + )); + + // Plane + commands.spawn(( + Mesh3d(meshes.add(Plane3d::default().mesh().size(10.0, 10.0))), + MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), + Transform::IDENTITY, + Collider::cuboid(10.0, 0.2, 10.0), + NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. + )); + + commands.spawn(( + Mesh3d(meshes.add(Plane3d::default().mesh().size(10.0, 10.0))), + MeshMaterial3d(materials.add(Color::srgb(0.68, 0.68, 1.0))), + Transform::from_xyz(0.0, 6.0, 0.0), + Collider::cuboid(10.0, 0.2, 10.0), + NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. + )); +} + +fn spawn_or_despawn_affector_system( + keys: Res>, + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + mut spawned_entity: Local>, +) { + if !keys.just_pressed(KeyCode::KeyX) { + return; + } + + if let Some(entity) = *spawned_entity { + commands.entity(entity).despawn_recursive(); + *spawned_entity = None; + } else { + let entity = commands + .spawn(( + Mesh3d(meshes.add(Cuboid::new(2.5, 2.5, 2.5))), + MeshMaterial3d(materials.add(Color::srgb(1.0, 0.1, 0.5))), + Transform::from_xyz(5.0, 0.8, -5.0), + Collider::cuboid(2.5, 2.5, 2.5), + NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. + )) + .id(); + + *spawned_entity = Some(entity); + } +} + +fn print_controls() { + info!("========================================="); + info!("| Press A to run ASYNC path finding. |"); + info!("| Press B to run BLOCKING path finding. |"); + info!("| Press M to toggle drawing nav-mesh. |"); + info!("| Press X to spawn or despawn red cube. |"); + info!("========================================="); +} diff --git a/examples/parry3d.rs b/examples/parry3d.rs index e479e6c..60b73f2 100644 --- a/examples/parry3d.rs +++ b/examples/parry3d.rs @@ -1,12 +1,17 @@ //! A simple example showing how to use oxidized_navigation with a custom component using parry3d colliders. +//! Press M to draw nav-mesh. +//! Press X to spawn or despawn red cube. -use bevy::{math::primitives, prelude::*}; +use bevy::prelude::*; use oxidized_navigation::{ colliders::OxidizedCollider, debug_draw::{DrawNavMesh, OxidizedNavigationDebugDrawPlugin}, NavMeshAffector, NavMeshSettings, OxidizedNavigationPlugin, }; -use crate::parry::parry3d::shape::SharedShape; +use parry3d::{ + bounding_volume::Aabb, + shape::{SharedShape, TypedShape}, +}; fn main() { App::new() @@ -26,7 +31,7 @@ fn main() { .add_systems(Startup, setup) .add_systems( Update, - (toggle_nav_mesh_system, spawn_or_despawn_affector_system), + (toggle_nav_mesh_debug_draw, spawn_or_despawn_affector_system), ) .run(); } @@ -37,11 +42,11 @@ struct MyParryCollider { } impl OxidizedCollider for MyParryCollider { - fn oxidized_into_typed_shape(&self) -> parry3d::shape::TypedShape { + fn oxidized_into_typed_shape(&self) -> TypedShape { self.collider.as_typed_shape() } - fn oxidized_compute_local_aabb(&self) -> parry3d::bounding_volume::Aabb { + fn oxidized_compute_local_aabb(&self) -> Aabb { self.collider.compute_local_aabb() } } @@ -53,63 +58,59 @@ fn setup( ) { print_controls(); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(4.0, 10.0, 15.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); + // Camera + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(4.0, 10.0, 15.0).looking_at(Vec3::ZERO, Vec3::Y), + )); - commands.spawn(DirectionalLightBundle { - directional_light: DirectionalLight { + // Directional light + commands.spawn(( + DirectionalLight { shadows_enabled: true, ..default() }, - transform: Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), - ..default() - }); + Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), + )); + // Ground plane commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Rectangle::from_size(Vec2::new(20.0, 20.0))), - material: materials.add(Color::srgb(0.3, 0.5, 0.3)), - ..default() - }, + Mesh3d(meshes.add(Plane3d::default().mesh().size(20.0, 20.0))), + MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), + Transform::IDENTITY, MyParryCollider { collider: SharedShape::cuboid(10.0, 0.1, 10.0), }, - NavMeshAffector, + NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); + + // Cube commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(2.0, 2.0, 2.0)), - material: materials.add(Color::srgb(0.4, 0.5, 0.9)), - transform: Transform::from_xyz(2.0, 1.0, -3.0), - ..default() - }, + Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))), + MeshMaterial3d(materials.add(Color::srgb(0.4, 0.5, 0.9))), + Transform::from_xyz(-5.0, 0.8, -5.0), MyParryCollider { collider: SharedShape::cuboid(1.0, 1.0, 1.0), }, - NavMeshAffector, + NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); + // Thin wall commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(0.1, 0.1, 0.1)), - material: materials.add(Color::srgb(0.4, 0.8, 0.9)), - transform: Transform::from_xyz(-3.0, 0.6, 3.0).with_scale(Vec3::new(30.0, 12.0, 1.0)), - ..default() - }, + Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.1))), + MeshMaterial3d(materials.add(Color::srgb(0.4, 0.8, 0.9))), + Transform::from_xyz(-3.0, 0.6, 3.0).with_scale(Vec3::new(30.0, 12.0, 1.0)), MyParryCollider { - collider: SharedShape::cuboid(1.5, 0.6, 0.05), + collider: SharedShape::cuboid(1.0, 1.0, 1.0), }, - NavMeshAffector, + NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); } -// -// Toggle drawing Nav-mesh. -// Press M to toggle drawing the navmesh. -// -fn toggle_nav_mesh_system(keys: Res>, mut show_navmesh: ResMut) { +fn toggle_nav_mesh_debug_draw( + keys: Res>, + mut show_navmesh: ResMut, +) { if keys.just_pressed(KeyCode::KeyM) { show_navmesh.0 = !show_navmesh.0; } @@ -132,12 +133,9 @@ fn spawn_or_despawn_affector_system( } else { let entity = commands .spawn(( - PbrBundle { - mesh: meshes.add(Mesh::from(primitives::Cuboid::new(2.5, 2.5, 2.5))), - material: materials.add(Color::srgb(1.0, 0.1, 0.5)), - transform: Transform::from_xyz(5.0, 0.8, 5.0), - ..default() - }, + Mesh3d(meshes.add(Mesh::from(Cuboid::new(2.5, 2.5, 2.5)))), + MeshMaterial3d(materials.add(Color::srgb(1.0, 0.1, 0.5))), + Transform::from_xyz(5.0, 0.8, 5.0), MyParryCollider { collider: SharedShape::cuboid(1.25, 1.25, 1.25), }, diff --git a/examples/rapier3d.rs b/examples/rapier3d.rs index 40caaab..608463a 100644 --- a/examples/rapier3d.rs +++ b/examples/rapier3d.rs @@ -8,7 +8,10 @@ use std::sync::{Arc, RwLock}; use bevy::{ - color::palettes, math::primitives, prelude::*, tasks::{AsyncComputeTaskPool, Task} + color::palettes, + math::primitives, + prelude::*, + tasks::{AsyncComputeTaskPool, Task}, }; // use bevy_editor_pls::EditorPlugin; use bevy::tasks::futures_lite::future; @@ -219,53 +222,44 @@ fn setup_world_system( ) { print_controls(); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(10.0, 10.0, 15.0) - .looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), - ..default() - }); + // Camera + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(10.0, 10.0, 15.0).looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), + )); - commands.spawn(DirectionalLightBundle { - directional_light: DirectionalLight { + // Directional light + commands.spawn(( + DirectionalLight { shadows_enabled: true, ..default() }, - transform: Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), - ..default() - }); + Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), + )); - // Plane + // Ground plane commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Rectangle::from_size(Vec2::new(50.0, 50.0))), - material: materials.add(Color::srgb(0.3, 0.5, 0.3)), - transform: Transform::IDENTITY, - ..default() - }, + Mesh3d(meshes.add(Plane3d::default().mesh().size(50.0, 50.0))), + MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), + Transform::IDENTITY, Collider::cuboid(25.0, 0.1, 25.0), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); // Cube commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5)), - material: materials.add(Color::srgb(0.1, 0.1, 0.5)), - transform: Transform::from_xyz(-5.0, 0.8, -5.0), - ..default() - }, + Mesh3d(meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5))), + MeshMaterial3d(materials.add(Color::srgb(0.1, 0.1, 0.5))), + Transform::from_xyz(-5.0, 0.8, -5.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); // Thin wall commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(0.1, 0.1, 0.1)), - material: materials.add(Color::srgb(0.1, 0.1, 0.5)), - transform: Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), - ..default() - }, + Mesh3d(meshes.add(Mesh::from(primitives::Cuboid::new(0.1, 0.1, 0.1)))), + MeshMaterial3d(materials.add(Color::srgb(0.1, 0.1, 0.5))), + Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), Collider::cuboid(0.05, 0.05, 0.05), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); @@ -288,12 +282,9 @@ fn spawn_or_despawn_affector_system( } else { let entity = commands .spawn(( - PbrBundle { - mesh: meshes.add(Mesh::from(primitives::Cuboid::new(2.5, 2.5, 2.5))), - material: materials.add(Color::srgb(1.0, 0.1, 0.5)), - transform: Transform::from_xyz(5.0, 0.8, 0.0), - ..default() - }, + Mesh3d(meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5))), + MeshMaterial3d(materials.add(Color::srgb(1.0, 0.1, 0.5))), + Transform::from_xyz(5.0, 0.8, 0.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )) diff --git a/examples/rapier3d_heightfield.rs b/examples/rapier3d_heightfield.rs index 72b6806..839dd37 100644 --- a/examples/rapier3d_heightfield.rs +++ b/examples/rapier3d_heightfield.rs @@ -215,17 +215,13 @@ fn draw_nav_mesh_system(keys: Res>, mut draw_nav_mesh: ResM fn setup_world_system(mut commands: Commands) { // light - commands.spawn(PointLightBundle { - transform: Transform::from_xyz(4.0, 8.0, 4.0), - ..default() - }); + commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 8.0, 4.0))); // Camera - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(60.0, 50.0, 50.0) - .looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), - ..default() - }); + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(60.0, 50.0, 50.0).looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), + )); let heightfield_heights = (0..(50 * 50)) .map(|value| { @@ -237,7 +233,7 @@ fn setup_world_system(mut commands: Commands) { // Heightfield. commands.spawn(( - TransformBundle::from_transform(Transform::from_xyz(0.0, 0.0, 0.0)), + Transform::from_xyz(0.0, 0.0, 0.0), Collider::heightfield(heightfield_heights, 50, 50, Vec3::new(50.0, 50.0, 50.0)), NavMeshAffector, )); @@ -260,12 +256,9 @@ fn spawn_or_despawn_affector_system( } else { let entity = commands .spawn(( - PbrBundle { - mesh: meshes.add(Mesh::from(primitives::Cuboid::new(2.5, 2.5, 2.5))), - material: materials.add(Color::srgb(1.0, 0.1, 0.5)), - transform: Transform::from_xyz(5.0, 0.8, -5.0), - ..default() - }, + Mesh3d(meshes.add(Mesh::from(primitives::Cuboid::new(2.5, 2.5, 2.5)))), + MeshMaterial3d(materials.add(Color::srgb(1.0, 0.1, 0.5))), + Transform::from_xyz(5.0, 0.8, -5.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )) diff --git a/examples/rapier3d_multi_floor.rs b/examples/rapier3d_multi_floor.rs index 0a28b1f..4530e2e 100644 --- a/examples/rapier3d_multi_floor.rs +++ b/examples/rapier3d_multi_floor.rs @@ -7,7 +7,9 @@ use std::sync::{Arc, RwLock}; use bevy::{ - color::palettes, math::primitives, prelude::*, tasks::{AsyncComputeTaskPool, Task} + color::palettes, + prelude::*, + tasks::{AsyncComputeTaskPool, Task}, }; // use bevy_editor_pls::EditorPlugin; use bevy::tasks::futures_lite::future; @@ -218,40 +220,32 @@ fn setup_world_system( ) { print_controls(); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(15.0, 10.0, 20.0) - .looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), - ..default() - }); + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(15.0, 10.0, 20.0).looking_at(Vec3::new(0.0, 2.0, 0.0), Vec3::Y), + )); - commands.spawn(DirectionalLightBundle { - directional_light: DirectionalLight { + commands.spawn(( + DirectionalLight { shadows_enabled: true, ..default() }, - transform: Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), - ..default() - }); + Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, -0.5, 0.0)), + )); // Plane commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Rectangle::from_size(Vec2::new(10.0, 10.0))), - material: materials.add(Color::srgb(0.3, 0.5, 0.3)), - transform: Transform::IDENTITY, - ..default() - }, - Collider::cuboid(5.0, 0.1, 5.0), + Mesh3d(meshes.add(Plane3d::default().mesh().size(25.0, 25.0))), + MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), + Transform::IDENTITY, + Collider::cuboid(12.5, 0.1, 12.5), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); commands.spawn(( - PbrBundle { - mesh: meshes.add(primitives::Rectangle::from_size(Vec2::new(10.0, 10.0))), - material: materials.add(Color::srgb(0.68, 0.68, 1.0)), - transform: Transform::from_xyz(0.0, 6.0, 0.0), - ..default() - }, + Mesh3d(meshes.add(Plane3d::default().mesh().size(10.0, 10.0))), + MeshMaterial3d(materials.add(Color::srgb(0.68, 0.68, 1.0))), + Transform::from_xyz(0.0, 6.0, 0.0), Collider::cuboid(5.0, 0.1, 5.0), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )); @@ -274,12 +268,9 @@ fn spawn_or_despawn_affector_system( } else { let entity = commands .spawn(( - PbrBundle { - mesh: meshes.add(primitives::Cuboid::new(2.5, 2.5, 2.5)), - material: materials.add(Color::srgb(1.0, 0.1, 0.5)), - transform: Transform::from_xyz(5.0, 0.8, -5.0), - ..default() - }, + Mesh3d(meshes.add(Cuboid::new(2.5, 2.5, 2.5))), + MeshMaterial3d(materials.add(Color::srgb(1.0, 0.1, 0.5))), + Transform::from_xyz(5.0, 0.8, -5.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, // Only entities with a NavMeshAffector component will contribute to the nav-mesh. )) diff --git a/src/colliders/avian.rs b/src/colliders/avian.rs index 5223359..200764c 100644 --- a/src/colliders/avian.rs +++ b/src/colliders/avian.rs @@ -1,8 +1,8 @@ -use crate::parry::parry3d::{bounding_volume::Aabb, shape::TypedShape}; +use parry3d::{bounding_volume::Aabb, shape::TypedShape}; use super::OxidizedCollider; -/// This is only compiled and available when the "xpbd" feature is enabled. +/// This is only compiled and available when the "avian" feature is enabled. impl OxidizedCollider for avian3d::prelude::Collider { fn oxidized_into_typed_shape(&self) -> TypedShape { self.shape_scaled().as_typed_shape() diff --git a/src/colliders/mod.rs b/src/colliders/mod.rs index b7d52f5..36f0e7d 100644 --- a/src/colliders/mod.rs +++ b/src/colliders/mod.rs @@ -1,11 +1,11 @@ use bevy::prelude::Component; -#[cfg(feature = "rapier")] -pub mod rapier; #[cfg(feature = "avian")] pub mod avian; +#[cfg(feature = "rapier")] +pub mod rapier; -/// The trait that is require to implement for the collider component that you want to use with oxidized-navigation. +/// The trait that is required to implement for the collider component that you want to use with oxidized-navigation. /// Essentially it allows you to use any bevy component that contains a `parry3d::shape::SharedShape` as a collider. /// /// This trait is already implemented for `bevy_rapier3d::prelude::Collider` and `avian::prelude::Collider`. @@ -13,7 +13,7 @@ pub mod avian; /// See the parry3d example for how to implement this trait for a custom component that wraps a `parry3d::shape::SharedShape`. pub trait OxidizedCollider: Component { // Names are changed to avoid conflicting with the function calls on a `parry3d::shape::SharedShape`. - fn oxidized_into_typed_shape(&self) -> crate::parry::parry3d::shape::TypedShape; + fn oxidized_into_typed_shape(&self) -> parry3d::shape::TypedShape; - fn oxidized_compute_local_aabb(&self) -> crate::parry::parry3d::bounding_volume::Aabb; + fn oxidized_compute_local_aabb(&self) -> parry3d::bounding_volume::Aabb; } diff --git a/src/colliders/rapier.rs b/src/colliders/rapier.rs index 6a8e5f4..1fbd18d 100644 --- a/src/colliders/rapier.rs +++ b/src/colliders/rapier.rs @@ -1,4 +1,4 @@ -use crate::parry::parry3d::{bounding_volume::Aabb, shape::TypedShape}; +use parry3d::{bounding_volume::Aabb, shape::TypedShape}; use super::OxidizedCollider; diff --git a/src/contour.rs b/src/contour.rs index d47b80e..679591e 100644 --- a/src/contour.rs +++ b/src/contour.rs @@ -11,8 +11,8 @@ use crate::{ Area, }; -use super::{NavMeshSettings, FLAG_BORDER_VERTEX, MASK_CONTOUR_REGION}; use super::math::{in_cone, intersect}; +use super::{NavMeshSettings, FLAG_BORDER_VERTEX, MASK_CONTOUR_REGION}; #[derive(Default, Clone, Debug)] pub struct Contour { diff --git a/src/conversion.rs b/src/conversion.rs index 056d77c..e2989fc 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -1,5 +1,5 @@ use bevy::prelude::{Transform, Vec3}; -use crate::parry::parry3d::{ +use parry3d::{ math::Real, na::Point3, shape::{Ball, Capsule, Cone, Cuboid, Cylinder, Triangle}, diff --git a/src/heightfields.rs b/src/heightfields.rs index 812fb1d..17d868b 100644 --- a/src/heightfields.rs +++ b/src/heightfields.rs @@ -1,7 +1,7 @@ use std::{cmp::Ordering, ops::Div, sync::Arc}; use bevy::{math::Vec3A, prelude::*}; -use crate::parry::parry3d::shape::HeightField; +use parry3d::shape::HeightField; use smallvec::SmallVec; use crate::{conversion::Triangles, Area}; @@ -168,6 +168,7 @@ pub(super) fn build_heightfield_tile( voxel_tile } +#[allow(clippy::too_many_arguments)] fn process_triangle( a: Vec3A, b: Vec3A, diff --git a/src/lib.rs b/src/lib.rs index 67ecc22..0123d89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ use heightfields::{ erode_walkable_area, HeightFieldCollection, }; use mesher::build_poly_mesh; -use crate::parry::parry3d::{math::Isometry, na::Vector3,shape::TypedShape}; +use parry3d::{math::Isometry, na::Vector3, shape::TypedShape}; use regions::build_regions; use smallvec::SmallVec; use tiles::{create_nav_mesh_tile_from_poly_mesh, NavMeshTile, NavMeshTiles}; @@ -76,12 +76,11 @@ pub mod conversion; #[cfg(feature = "debug_draw")] pub mod debug_draw; mod heightfields; +mod math; mod mesher; -mod parry; pub mod query; mod regions; pub mod tiles; -mod math; /// System sets containing the crate's systems. #[derive(SystemSet, Debug, PartialEq, Eq, Hash, Clone)] @@ -128,7 +127,7 @@ where app.add_systems( Update, handle_removed_affectors_system - .run_if(any_component_removed::()) + .run_if(any_component_removed::) .before(send_tile_rebuild_tasks_system::) .in_set(OxidizedNavigation::RemovedComponent), ); @@ -426,22 +425,21 @@ impl NavMesh { } } +type NavmeshAffectorChangedQueryFilter = ( + Or<( + Changed, + Changed, + Changed, + )>, + With, +); + fn update_navmesh_affectors_system( nav_mesh_settings: Res, mut tile_affectors: ResMut, mut affector_relations: ResMut, mut dirty_tiles: ResMut, - mut query: Query< - (Entity, &C, &GlobalTransform), - ( - Or<( - Changed, - Changed, - Changed, - )>, - With, - ), - >, + mut query: Query<(Entity, &C, &GlobalTransform), NavmeshAffectorChangedQueryFilter>, ) { // Expand by 2 * walkable_radius to match with erode_walkable_area. let border_expansion = @@ -547,6 +545,7 @@ fn can_generate_new_tiles( && !dirty_tiles.0.is_empty() } +#[allow(clippy::too_many_arguments)] fn send_tile_rebuild_tasks_system( mut active_generation_tasks: ResMut, mut generation_ticker: ResMut, @@ -711,14 +710,14 @@ fn send_tile_rebuild_tasks_system( } /// Event containing the tile coordinate of a generated/regenerated tile. -/// +/// /// Emitted when a tile has been updated. #[derive(Event)] pub struct TileGenerated(pub UVec2); fn remove_finished_tasks( mut active_generation_tasks: ResMut, - mut event: EventWriter + mut event: EventWriter, ) { active_generation_tasks.0.retain_mut(|task| { if let Some(tile) = future::block_on(future::poll_once(task)) { @@ -775,7 +774,7 @@ async fn build_tile( nav_mesh.tile_generations.insert(tile_coord, generation); nav_mesh.add_tile(tile_coord, nav_mesh_tile, &nav_mesh_settings); - + Some(tile_coord) } else { None @@ -862,4 +861,4 @@ fn get_neighbour_index(tile_size: usize, index: usize, dir: usize) -> usize { 3 => index - tile_size, _ => panic!("Not a valid direction"), } -} \ No newline at end of file +} diff --git a/src/parry.rs b/src/parry.rs deleted file mode 100644 index 6fc5aec..0000000 --- a/src/parry.rs +++ /dev/null @@ -1,12 +0,0 @@ - -cfg_if::cfg_if! { - if #[cfg(all(feature = "parry_016", feature = "parry_015"))] { - compile_error!("You must pick a single parry3d feature."); - } else if #[cfg(feature = "parry_015")] { - pub use parry3d_015 as parry3d; - } else if #[cfg(feature = "parry_016")] { - pub use parry3d_016 as parry3d; - } else { - compile_error!("You must enabled either the `parry_015` or `parry_016` feature matching, whichever matches your Parry3d version."); - } -} diff --git a/src/regions.rs b/src/regions.rs index c3ca49b..a9442d7 100644 --- a/src/regions.rs +++ b/src/regions.rs @@ -759,6 +759,7 @@ fn add_unique_floor_region(region: &mut Region, region_id: u16) { region.floors.push(region_id); } +#[allow(clippy::too_many_arguments)] fn flood_region( tile_side: usize, entry: LevelStackEntry, diff --git a/tests/avian.rs b/tests/avian.rs index cb8ea66..c24113d 100644 --- a/tests/avian.rs +++ b/tests/avian.rs @@ -1,7 +1,7 @@ use std::{num::NonZeroU16, time::Duration}; -use bevy::prelude::*; use avian3d::prelude::{Collider, PhysicsPlugins}; +use bevy::prelude::*; use oxidized_navigation::{ query::find_path, ActiveGenerationTasks, NavMesh, NavMeshAffector, NavMeshSettings, OxidizedNavigationPlugin, @@ -13,32 +13,28 @@ const SLEEP_DURATION: Duration = Duration::from_millis(2); fn setup_world_system(mut commands: Commands) { // Plane commands.spawn(( - TransformBundle::IDENTITY, + Transform::IDENTITY, Collider::cuboid(25.0, 0.1, 25.0), NavMeshAffector, )); // Cube commands.spawn(( - TransformBundle::from_transform(Transform::from_xyz(-5.0, 0.8, -5.0)), + Transform::from_xyz(-5.0, 0.8, -5.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, )); // Tall Cube commands.spawn(( - TransformBundle::from_transform( - Transform::from_xyz(-0.179, 18.419, -27.744).with_scale(Vec3::new(15.0, 15.0, 15.0)), - ), + Transform::from_xyz(-0.179, 18.419, -27.744).with_scale(Vec3::new(15.0, 15.0, 15.0)), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, )); // Thin wall commands.spawn(( - TransformBundle::from_transform( - Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), - ), + Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), Collider::cuboid(0.05, 0.05, 0.05), NavMeshAffector, )); @@ -65,7 +61,7 @@ fn setup_app(app: &mut App) { max_tile_generation_tasks: NonZeroU16::new(8), // Github Actions are limited to 7 GB. }), PhysicsPlugins::default(), - HierarchyPlugin::default() + HierarchyPlugin::default(), )); } diff --git a/tests/parry3d.rs b/tests/parry3d.rs index 035ee18..a5df692 100644 --- a/tests/parry3d.rs +++ b/tests/parry3d.rs @@ -5,7 +5,10 @@ use oxidized_navigation::{ colliders::OxidizedCollider, query::find_path, ActiveGenerationTasks, NavMesh, NavMeshAffector, NavMeshSettings, OxidizedNavigationPlugin, }; -use parry3d_016::shape::SharedShape; +use parry3d::{ + bounding_volume::Aabb, + shape::{SharedShape, TypedShape}, +}; const TIMEOUT_DURATION: Duration = Duration::new(15, 0); const SLEEP_DURATION: Duration = Duration::from_millis(2); @@ -16,11 +19,11 @@ struct MyParryCollider { } impl OxidizedCollider for MyParryCollider { - fn oxidized_into_typed_shape(&self) -> parry3d_016::shape::TypedShape { + fn oxidized_into_typed_shape(&self) -> TypedShape { self.collider.as_typed_shape() } - fn oxidized_compute_local_aabb(&self) -> parry3d_016::bounding_volume::Aabb { + fn oxidized_compute_local_aabb(&self) -> Aabb { self.collider.compute_local_aabb() } } @@ -28,7 +31,7 @@ impl OxidizedCollider for MyParryCollider { fn setup_world_system(mut commands: Commands) { // Plane commands.spawn(( - TransformBundle::IDENTITY, + Transform::IDENTITY, MyParryCollider { collider: SharedShape::cuboid(25.0, 0.1, 25.0), }, @@ -37,7 +40,7 @@ fn setup_world_system(mut commands: Commands) { // Cube commands.spawn(( - TransformBundle::from_transform(Transform::from_xyz(-5.0, 0.8, -5.0)), + Transform::from_xyz(-5.0, 0.8, -5.0), MyParryCollider { collider: SharedShape::cuboid(1.25, 1.25, 1.25), }, @@ -46,9 +49,7 @@ fn setup_world_system(mut commands: Commands) { // Tall Cube commands.spawn(( - TransformBundle::from_transform( - Transform::from_xyz(-0.179, 18.419, -27.744).with_scale(Vec3::new(15.0, 15.0, 15.0)), - ), + Transform::from_xyz(-0.179, 18.419, -27.744).with_scale(Vec3::new(15.0, 15.0, 15.0)), MyParryCollider { collider: SharedShape::cuboid(1.25, 1.25, 1.25), }, @@ -57,9 +58,7 @@ fn setup_world_system(mut commands: Commands) { // Thin wall commands.spawn(( - TransformBundle::from_transform( - Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), - ), + Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), MyParryCollider { collider: SharedShape::cuboid(0.05, 0.05, 0.05), }, diff --git a/tests/rapier3d.rs b/tests/rapier3d.rs index eb809e5..adf6d0b 100644 --- a/tests/rapier3d.rs +++ b/tests/rapier3d.rs @@ -13,32 +13,28 @@ const SLEEP_DURATION: Duration = Duration::from_millis(2); fn setup_world_system(mut commands: Commands) { // Plane commands.spawn(( - TransformBundle::IDENTITY, + Transform::IDENTITY, Collider::cuboid(25.0, 0.1, 25.0), NavMeshAffector, )); // Cube commands.spawn(( - TransformBundle::from_transform(Transform::from_xyz(-5.0, 0.8, -5.0)), + Transform::from_xyz(-5.0, 0.8, -5.0), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, )); // Tall Cube commands.spawn(( - TransformBundle::from_transform( - Transform::from_xyz(-0.179, 18.419, -27.744).with_scale(Vec3::new(15.0, 15.0, 15.0)), - ), + Transform::from_xyz(-0.179, 18.419, -27.744).with_scale(Vec3::new(15.0, 15.0, 15.0)), Collider::cuboid(1.25, 1.25, 1.25), NavMeshAffector, )); // Thin wall commands.spawn(( - TransformBundle::from_transform( - Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), - ), + Transform::from_xyz(-3.0, 0.8, 5.0).with_scale(Vec3::new(50.0, 15.0, 1.0)), Collider::cuboid(0.05, 0.05, 0.05), NavMeshAffector, )); @@ -55,7 +51,7 @@ fn setup_heightfield_system(mut commands: Commands) { // Heightfield. commands.spawn(( - TransformBundle::from_transform(Transform::from_xyz(0.0, 0.0, 0.0)), + Transform::from_xyz(0.0, 0.0, 0.0), Collider::heightfield(heightfield_heights, 50, 50, Vec3::new(50.0, 50.0, 50.0)), NavMeshAffector, ));