Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: minor path finding improvements #120

Merged
merged 6 commits into from
May 7, 2024
Merged
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/ryot_assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@

use bevy_asset_loader::asset_collection::AssetCollection;
use bevy_ecs::prelude::Resource;
use ryot_utils::prelude::*;

pub mod atlas;
pub mod catalog;
pub mod sprites;
pub mod visual_elements;

pub trait RyotAsset = Resource + AssetCollection + Send + Sync + 'static;
pub trait RyotAsset = Resource + AssetCollection + ThreadSafe;

pub mod prelude {
pub use crate::{
Expand Down
1 change: 1 addition & 0 deletions crates/ryot_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ bevy_render = { workspace = true, optional = true }
bevy_sprite = { workspace = true, optional = true }
bevy_utils = { workspace = true, optional = true }
bevy_asset_loader = { workspace = true, optional = true }
ryot_utils.workspace = true

async-std = "1.12.0"
derive_more.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/ryot_core/src/game/navigable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
/// }
/// }
/// ```
pub trait Navigable: Sync + Send + 'static {
pub trait Navigable: ryot_utils::ThreadSafe {
fn is_walkable(&self) -> bool {
true
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ryot_pathfinder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pathfinding algorithm:
- **to**: target position.
- **cardinal_cost**: cost of moving in the cardinal directions.
- **diagonal_cost**: cost of moving in the diagonal directions.
- **success_distance**: distance from the target position that is considered a successful pathfinding computation.
- **success_range**: distance range from the target position that is considered a successful pathfinding computation.
- **timeout**: maximum time in seconds that the pathfinding algorithm can run before returning None.

It's part of the public API and should be used by the user to trigger pathfinding computations.
Expand Down
22 changes: 16 additions & 6 deletions crates/ryot_pathfinder/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct PathFindingQuery<P: Pathable> {
pub to: P,
pub cardinal_cost: u32,
pub diagonal_cost: u32,
pub success_distance: f32,
pub success_range: (f32, f32),
pub timeout: Option<Duration>,
}

Expand All @@ -76,10 +76,9 @@ pub struct PathFindingQuery<P: Pathable> {
/// };
///
/// path.remove(0);
/// // do something with next_pos
/// }
/// }
#[derive(Component, Clone, Debug, Deref, DerefMut)]
#[derive(Component, Clone, Default, Debug, Deref, DerefMut)]
pub struct Path<P: Pathable>(pub(crate) Vec<P>);

/// Manages the asynchronous execution of pathfinding tasks, holding a future
Expand All @@ -94,7 +93,7 @@ impl<P: Pathable + Default> Default for PathFindingQuery<P> {
timeout: None,
cardinal_cost: 1,
diagonal_cost: 500,
success_distance: 1.,
success_range: (1., 1.),
}
}
}
Expand All @@ -109,6 +108,10 @@ impl<P: Pathable + Default> PathFindingQuery<P> {
}

impl<P: Pathable> PathFindingQuery<P> {
pub fn with_target(self, to: P) -> Self {
Self { to, ..self }
}

pub fn with_timeout(self, timeout: Duration) -> Self {
Self {
timeout: Some(timeout),
Expand All @@ -130,9 +133,16 @@ impl<P: Pathable> PathFindingQuery<P> {
}
}

pub fn with_success_distance(self, success_distance: f32) -> Self {
pub fn with_success_distance(self, distance: f32) -> Self {
Self {
success_range: (distance, distance),
..self
}
}

pub fn with_success_range(self, success_range: (f32, f32)) -> Self {
Self {
success_distance,
success_range,
..self
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ryot_pathfinder/src/pathable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use ryot_utils::prelude::*;
/// Trait for elements that can engage in pathfinding, providing a method to determine the path
/// between two Points and if the current Pathable can be navigated based on a given Navigable.
/// This trait depends on Point, which is a trait that represents a position in the world.
pub trait Pathable: Point + Sync + Send + 'static {
pub trait Pathable: Point + ThreadSafe {
/// Calculates the path between two points, based on the provided query and a validator function
/// that determines if a point is pathable. The path is returned as a vector of points and the
/// total cost of the path.
Expand Down
22 changes: 11 additions & 11 deletions crates/ryot_pathfinder/src/two_d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ use std::time::Instant;
/// Calculates a 2D path using the A* algorithm, optimized for grid-based environments.
/// This function provides default pathfinding behavior which can be overridden for
/// customized pathfinding logic or non-grid environments.
pub fn find_path_2d<
P: Pathable,
FV: Fn(&P) -> bool,
FN: Fn(&P, &FV, &PathFindingQuery<P>) -> Vec<(P, u32)>,
>(
pub fn find_path_2d<P: Pathable, FV: Fn(&P) -> bool, FN: Fn(&P, &FV, u32, u32) -> Vec<(P, u32)>>(
from: &P,
query: &PathFindingQuery<P>,
validator: &FV,
Expand All @@ -33,10 +29,13 @@ pub fn find_path_2d<
from,
|next| match query.timeout {
Some(timeout) if Instant::now().duration_since(start) > timeout => vec![],
_ => neighbors_generator(next, validator, query),
_ => neighbors_generator(next, validator, query.cardinal_cost, query.diagonal_cost),
},
|next| (distance(&query.to, next) / 3.) as u32,
|next| {
distance(&query.to, next) >= query.success_range.0
&& distance(&query.to, next) <= query.success_range.0
},
|next| distance(&query.to, next) as u32,
|next| distance(&query.to, next) <= query.success_distance,
)
}

Expand All @@ -45,7 +44,8 @@ pub fn find_path_2d<
pub fn weighted_neighbors_2d_generator<P: Pathable, F: Fn(&P) -> bool + ?Sized>(
pathable: &P,
validator: &F,
query: &PathFindingQuery<P>,
cardinal_cost: u32,
diagonal_cost: u32,
) -> Vec<(P, u32)> {
let (x, y, z) = pathable.coordinates();

Expand All @@ -56,7 +56,7 @@ pub fn weighted_neighbors_2d_generator<P: Pathable, F: Fn(&P) -> bool + ?Sized>(
P::generate(x, y - 1, z),
]
.iter()
.map(|p| (*p, query.cardinal_cost))
.map(|p| (*p, cardinal_cost))
.collect::<Vec<(P, u32)>>();

cardinal.extend(
Expand All @@ -67,7 +67,7 @@ pub fn weighted_neighbors_2d_generator<P: Pathable, F: Fn(&P) -> bool + ?Sized>(
P::generate(x - 1, y + 1, z),
]
.iter()
.map(|p| (*p, query.diagonal_cost))
.map(|p| (*p, diagonal_cost))
.collect::<Vec<(P, u32)>>(),
);

Expand Down
4 changes: 2 additions & 2 deletions crates/ryot_ray_casting/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ryot_utils::prelude::*;
/// Requires the `SimpleCache<RadialArea, Vec<Vec<P>>>` resource to be initialized.
pub trait RayCastingApp {
fn add_ray_casting<
Marker: Copy + Send + Sync + 'static,
Marker: Copy + ThreadSafe,
P: RayCastingPoint + Component,
N: Navigable + Copy + Default,
>(
Expand All @@ -19,7 +19,7 @@ pub trait RayCastingApp {

impl RayCastingApp for App {
fn add_ray_casting<
Marker: Copy + Send + Sync + 'static,
Marker: Copy + ThreadSafe,
P: RayCastingPoint + Component,
N: Navigable + Copy + Default,
>(
Expand Down
3 changes: 2 additions & 1 deletion crates/ryot_ray_casting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![feature(trait_alias)]
use bevy_math::bounding::Aabb3d;
use ryot_core::prelude::Point;
use ryot_utils::prelude::*;

mod app;
mod propagation;
Expand All @@ -18,7 +19,7 @@ mod tests;
#[cfg(feature = "stubs")]
pub mod stubs;

pub trait RayCastingPoint = Point + Into<Aabb3d> + Send + Sync + 'static;
pub trait RayCastingPoint = Point + Into<Aabb3d> + ThreadSafe;

pub mod prelude {
pub use crate::{
Expand Down
14 changes: 5 additions & 9 deletions crates/ryot_ray_casting/src/stubs/example_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ use bevy_ecs::change_detection::{Res, ResMut};
use bevy_ecs::prelude::{Commands, Component, Local, Query, With};
use glam::{UVec2, Vec2};
use ryot_core::prelude::*;
use ryot_utils::app::OptionalPlugin;
use ryot_utils::cache::Cache;
use ryot_utils::prelude::*;
use std::marker::PhantomData;

pub fn tile_size() -> UVec2 {
Expand All @@ -26,7 +25,7 @@ pub struct Obstacle;

#[derive(Clone)]
pub struct ExampleBuilder<
T: Copy + Send + Sync + 'static,
T: Copy + ThreadSafe,
P: RayCastingPoint + Component,
N: Navigable + Copy + Default,
> {
Expand All @@ -36,11 +35,8 @@ pub struct ExampleBuilder<
_marker: PhantomData<(T, N)>,
}

impl<
T: Copy + Send + Sync + 'static,
P: RayCastingPoint + Component,
N: Navigable + Copy + Default,
> Default for ExampleBuilder<T, P, N>
impl<T: Copy + ThreadSafe, P: RayCastingPoint + Component, N: Navigable + Copy + Default> Default
for ExampleBuilder<T, P, N>
{
fn default() -> Self {
Self {
Expand All @@ -53,7 +49,7 @@ impl<
}

impl<
T: Copy + Send + Sync + 'static,
T: Copy + ThreadSafe,
P: RayCastingPoint + Component + Into<Vec2>,
N: Navigable + Copy + Default,
> ExampleBuilder<T, P, N>
Expand Down
14 changes: 7 additions & 7 deletions crates/ryot_ray_casting/src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum RayCastingSystems {
/// maintaining an updated representation of the ray casting requests and their intersections.
///
/// Run as part of [`CacheSystems::UpdateCache`].
pub fn update_intersection_cache<T: Copy + Send + Sync + 'static, P: RayCastingPoint>(
pub fn update_intersection_cache<T: Copy + ThreadSafe, P: RayCastingPoint>(
mut intersection_cache: ResMut<SimpleCache<RadialArea<P>, Vec<Vec<P>>>>,
q_radial_areas: Query<&RayCasting<T, P>, Changed<RayCasting<T, P>>>,
) {
Expand All @@ -45,7 +45,7 @@ pub fn update_intersection_cache<T: Copy + Send + Sync + 'static, P: RayCastingP
///
/// Run as part of [`RayCastingSystems::Process`].
pub fn process_ray_casting<
T: Copy + Send + Sync + 'static,
T: Copy + ThreadSafe,
P: RayCastingPoint + Component,
N: Navigable + Copy + Default,
>(
Expand Down Expand Up @@ -79,14 +79,14 @@ pub fn process_ray_casting<
});

for (entity, positions) in rx.try_iter() {
commands.entity(entity).insert(positions);
commands.entity(entity).try_insert(positions);
}
}

/// Shares the results of ray casting requests with all the entities pointed to by the `shared_with`
/// field in the RayCasting component. This system is crucial for sharing the results of ray casting
/// requests across multiple entities.
pub fn share_results<T: Copy + Send + Sync + 'static, P: RayCastingPoint>(
pub fn share_results<T: Copy + ThreadSafe, P: RayCastingPoint>(
mut commands: Commands,
mut q_propagation: Query<(&RayCasting<T, P>, &mut RayPropagation<T, P>)>,
mut q_results: Query<&mut RayPropagation<T, P>, Without<RayCasting<T, P>>>,
Expand All @@ -107,13 +107,13 @@ pub fn share_results<T: Copy + Send + Sync + 'static, P: RayCastingPoint>(
result.area_of_interest.extend(shared.area_of_interest);
result.collisions.extend(shared.collisions);
} else {
commands.entity(entity).insert(shared);
commands.entity(entity).try_insert(shared);
}
}
}

/// This system removes the RayPropagation component from entities that no longer have a RayCasting.
pub fn remove_stale_results<T: Copy + Send + Sync + 'static, P: RayCastingPoint>(
pub fn remove_stale_results<T: Copy + ThreadSafe, P: RayCastingPoint>(
mut commands: Commands,
q_orphan_results: Query<Entity, (With<RayPropagation<T, P>>, Without<RayCasting<T, P>>)>,
) {
Expand All @@ -124,7 +124,7 @@ pub fn remove_stale_results<T: Copy + Send + Sync + 'static, P: RayCastingPoint>

/// This system removes the RayCasting component that are no longer valid, based on their execution
/// type and last execution time.
pub fn remove_stale_requests<T: Copy + Send + Sync + 'static, P: RayCastingPoint>(
pub fn remove_stale_requests<T: Copy + ThreadSafe, P: RayCastingPoint>(
mut commands: Commands,
q_ray_casting: Query<(Entity, &RayCasting<T, P>)>,
) {
Expand Down
2 changes: 1 addition & 1 deletion crates/ryot_tiled/src/drawing/brushes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub enum BrushParams<E: BrushItem> {

impl<E: BrushItem> BrushParams<E> {
pub fn get_size(&self, center: E) -> i32 {
let get_distance = |pos: TilePosition| center.get_position().distance(pos).abs() as i32;
let get_distance = |pos: TilePosition| center.get_position().distance(&pos).abs() as i32;

match self {
BrushParams::Size(size) => *size,
Expand Down
2 changes: 1 addition & 1 deletion crates/ryot_tiled/src/drawing/brushes/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn round<B: BrushItem>(params: BrushParams<B>, center: B) -> Vec<B> {

for x in center_pos.x.saturating_sub(size)..=center_pos.x.saturating_add(size) {
for y in center_pos.y.saturating_sub(size)..=center_pos.y.saturating_add(size) {
let distance = center_pos.distance(TilePosition::new(x, y, center_pos.z));
let distance = center_pos.distance(&TilePosition::new(x, y, center_pos.z));
if distance <= size as f32 {
elements.push(B::from_position(
center,
Expand Down
9 changes: 7 additions & 2 deletions crates/ryot_tiled/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub mod drawing;
pub mod flags;
pub mod map;
pub mod movement;
#[cfg(feature = "pathfinding")]
pub mod pathfinding;
#[cfg(feature = "ray_casting")]
pub mod ray_casting;

Expand Down Expand Up @@ -86,9 +88,12 @@ pub mod prelude {

#[cfg(feature = "ray_casting")]
pub use crate::ray_casting::{
tiled_ray_casting, tiled_visible_ray_casting, tiled_walkable_ray_casting, TiledRayCasting,
TiledRayCastingApp,
tiled_ray_casting, tiled_visible_ray_casting, tiled_walkable_ray_casting, TiledRadialArea,
TiledRayCasting, TiledRayCastingApp, TiledRayPropagation,
};

#[cfg(feature = "pathfinding")]
pub use crate::pathfinding::{TiledPath, TiledPathFindingQuery};
}

pub static TILE_SIZE: OnceLock<UVec2> = OnceLock::new();
Expand Down
2 changes: 1 addition & 1 deletion crates/ryot_tiled/src/map/position/interactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ryot_core::prelude::Point;
use std::collections::HashSet;

impl TilePosition {
pub fn distance(self, other: Self) -> f32 {
pub fn distance(self, other: &Self) -> f32 {
self.truncate()
.as_vec2()
.distance(other.truncate().as_vec2())
Expand Down
5 changes: 5 additions & 0 deletions crates/ryot_tiled/src/pathfinding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use crate::prelude::TilePosition;
use ryot_pathfinder::prelude::*;

pub type TiledPath = Path<TilePosition>;
pub type TiledPathFindingQuery = PathFindingQuery<TilePosition>;
8 changes: 6 additions & 2 deletions crates/ryot_tiled/src/ray_casting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ use bevy_app::App;
use ryot_core::game::Navigable;
use ryot_core::prelude::Flags;
use ryot_ray_casting::prelude::*;
use ryot_utils::prelude::ThreadSafe;

pub trait TiledRayCastingApp {
fn add_tiled_ray_casting<Marker: Copy + Send + Sync + 'static>(&mut self) -> &mut Self;
fn add_tiled_ray_casting<Marker: Copy + ThreadSafe>(&mut self) -> &mut Self;
}

impl TiledRayCastingApp for App {
fn add_tiled_ray_casting<Marker: Copy + Send + Sync + 'static>(&mut self) -> &mut Self {
fn add_tiled_ray_casting<Marker: Copy + ThreadSafe>(&mut self) -> &mut Self {
self.add_ray_casting::<Marker, TilePosition, Flags>()
}
}

pub type TiledRayCasting<Marker> = RayCasting<Marker, TilePosition>;
pub type TiledRayPropagation<Marker> = RayPropagation<Marker, TilePosition>;
pub type TiledRadialArea = RadialArea<TilePosition>;
pub type TiledPerspective = Perspective<TilePosition>;

pub fn tiled_ray_casting<Marker>(
area: RadialArea<TilePosition>,
Expand Down
Loading
Loading