Compare commits

..

No commits in common. "8e4369163a7b2c81227e50b0adb2a13b2f327e4f" and "041d9ffe7d081af5332b59f295659b21589f5c8f" have entirely different histories.

4 changed files with 77 additions and 125 deletions

View File

@ -298,11 +298,11 @@ pub trait PointLike {
fn y(&self) -> f32; fn y(&self) -> f32;
fn x_i32(&self) -> i32 { fn x_i32(&self) -> i32 {
self.x().trunc() as i32 self.x().round() as i32
} }
fn y_i32(&self) -> i32 { fn y_i32(&self) -> i32 {
self.y().trunc() as i32 self.y().round() as i32
} }
fn x_usize(&self) -> usize { fn x_usize(&self) -> usize {
@ -321,12 +321,12 @@ pub trait PointLike {
(self.x_i32(), self.y_i32()) (self.x_i32(), self.y_i32())
} }
fn trunc(&self) -> (f32, f32) { fn floor(&self) -> (f32, f32) {
(self.x().trunc(), self.y().trunc()) (self.x().floor(), self.y().floor())
} }
fn to_index(&self, width: usize) -> usize { fn to_index(&self, width: usize) -> usize {
(self.y_usize() * width) + self.x_usize() ((self.y_i32() * width as i32) + self.x_i32()) as usize
} }
fn distance_squared(&self, other: &dyn PointLike) -> f32 { fn distance_squared(&self, other: &dyn PointLike) -> f32 {

View File

@ -132,7 +132,7 @@ where
let mut features = features let mut features = features
.iter() .iter()
.filter(|v| visible_entities.contains(&v.0)) .filter(|v| visible_entities.contains(&v.0))
.map(|v| (v.1.trunc(), v.2)) .map(|v| (v.1.floor(), v.2))
.collect::<Vec<((f32, f32), &ExplorationType)>>(); .collect::<Vec<((f32, f32), &ExplorationType)>>();
if features.is_empty() { if features.is_empty() {
tts.speak("Nothing visible.", true)?; tts.speak("Nothing visible.", true)?;
@ -166,7 +166,7 @@ where
if let Some((coordinates, _)) = target { if let Some((coordinates, _)) = target {
commands commands
.entity(entity) .entity(entity)
.insert(Exploring(coordinates.trunc())); .insert(Exploring(coordinates.floor()));
} }
} }
Ok(()) Ok(())
@ -291,7 +291,7 @@ where
MapData: 'static + Clone + Default + Send + Sync, MapData: 'static + Clone + Default + Send + Sync,
{ {
if let Ok((coordinates, exploring, viewshed)) = explorer.get_single() { if let Ok((coordinates, exploring, viewshed)) = explorer.get_single() {
let coordinates = coordinates.trunc(); let coordinates = coordinates.floor();
let point = **exploring; let point = **exploring;
let shape = Collider::cuboid(0.5 - f32::EPSILON, 0.5 - f32::EPSILON); let shape = Collider::cuboid(0.5 - f32::EPSILON, 0.5 - f32::EPSILON);
let (known, idx) = if let Ok((map, revealed_tiles)) = map.get_single() { let (known, idx) = if let Ok((map, revealed_tiles)) = map.get_single() {

View File

@ -119,6 +119,12 @@ fn controls(
if let Some(pair) = actions.clamped_axis_pair(NavigationAction::Move) { if let Some(pair) = actions.clamped_axis_pair(NavigationAction::Move) {
cleanup = true; cleanup = true;
let mut direction = pair.xy(); let mut direction = pair.xy();
if direction.x.abs() < 0.5 {
direction.x = 0.;
}
if direction.y.abs() < 0.5 {
direction.y = 0.;
}
let forward_movement_factor = let forward_movement_factor =
forward_movement_factor.map(|v| v.0).unwrap_or_else(|| 1.); forward_movement_factor.map(|v| v.0).unwrap_or_else(|| 1.);
let backward_movement_factor = let backward_movement_factor =
@ -155,7 +161,6 @@ fn controls(
.action_data_mut(NavigationAction::Translate) .action_data_mut(NavigationAction::Translate)
.axis_pair = Some(DualAxisData::from_xy(translation)); .axis_pair = Some(DualAxisData::from_xy(translation));
} else { } else {
// println!("{entity:?}: SetLinearVelocity: {velocity:?}");
actions.press(NavigationAction::SetLinearVelocity); actions.press(NavigationAction::SetLinearVelocity);
actions actions
.action_data_mut(NavigationAction::SetLinearVelocity) .action_data_mut(NavigationAction::SetLinearVelocity)
@ -170,14 +175,13 @@ fn controls(
} }
if actions.pressed(NavigationAction::SetLinearVelocity) { if actions.pressed(NavigationAction::SetLinearVelocity) {
if let Some(pair) = actions.axis_pair(NavigationAction::SetLinearVelocity) { if let Some(pair) = actions.axis_pair(NavigationAction::SetLinearVelocity) {
// println!("{entity:?}: SetLinearVelocity: {pair:?}"); trace!("{entity:?}: SetLinearVelocity: {pair:?}");
velocity.linvel = pair.into(); velocity.linvel = pair.into();
} else { } else {
// println!("{entity:?}: SetLinearVelocity: 0");
velocity.linvel = Vec2::ZERO; velocity.linvel = Vec2::ZERO;
} }
} else if actions.just_released(NavigationAction::SetLinearVelocity) { } else if actions.just_released(NavigationAction::SetLinearVelocity) {
// println!("{entity:?}: Released velocity"); trace!("{entity:?}: Released velocity");
velocity.linvel = Vec2::ZERO; velocity.linvel = Vec2::ZERO;
actions actions
.action_data_mut(NavigationAction::SetLinearVelocity) .action_data_mut(NavigationAction::SetLinearVelocity)

View File

@ -15,7 +15,7 @@ use pathfinding::prelude::*;
use crate::{ use crate::{
commands::RunIfExistsExt, commands::RunIfExistsExt,
core::{PointLike, TransformExt}, core::PointLike,
map::{Map, MapObstruction}, map::{Map, MapObstruction},
navigation::{NavigationAction, RotationSpeed}, navigation::{NavigationAction, RotationSpeed},
}; };
@ -123,29 +123,22 @@ fn find_path_for_shape(
((x - 1, y + 1), 1.5), ((x - 1, y + 1), 1.5),
((x + 1, y + 1), 1.5), ((x + 1, y + 1), 1.5),
]; ];
let pos = Vector2::new(x as f32, y as f32);
let shape_pos = Isometry2::new(pos, 0.);
for exit in &exits { for exit in &exits {
let mut should_push = true; let mut should_push = true;
let dest = Vector2::new(exit.0 .0 as f32, exit.0 .1 as f32); let shape_pos =
let shape_vel = dest - pos; Isometry2::new(Vector2::new(exit.0 .0 as f32, exit.0 .1 as f32), 0.);
let max_toi = 1.; query_pipeline.intersections_with_shape(
if query_pipeline &rigid_body_set,
.cast_shape( &collider_set,
&rigid_body_set, &shape_pos,
&collider_set, &*shape.raw,
&shape_pos, bevy_rapier2d::rapier::pipeline::QueryFilter::new()
&shape_vel, .predicate(&|h, _c| h != initiator),
&*shape.raw, |_handle| {
max_toi, should_push = false;
true, false
bevy_rapier2d::rapier::pipeline::QueryFilter::new() },
.predicate(&|h, _c| h != initiator), );
)
.is_some()
{
should_push = false;
}
if should_push { if should_push {
let mut cost = exit.1 * 100.; let mut cost = exit.1 * 100.;
if let Some(cost_map) = cost_map { if let Some(cost_map) = cost_map {
@ -194,10 +187,6 @@ fn calculate_path(
.remove::<Destination>(); .remove::<Destination>();
continue; continue;
} }
trace!(
"Calculating path from {:?}",
coordinates.translation.truncate().i32()
);
let coordinates_clone = *coordinates; let coordinates_clone = *coordinates;
let destination_clone = *destination; let destination_clone = *destination;
let query_pipeline = rapier_context.query_pipeline.clone(); let query_pipeline = rapier_context.query_pipeline.clone();
@ -219,8 +208,10 @@ fn calculate_path(
} }
let shape_clone = (*shape).clone(); let shape_clone = (*shape).clone();
trace!( trace!(
"{entity:?}: path: calculating from {:?} to {destination:?}", "{:?}: path: calculating from {:?} to {:?}",
entity,
coordinates.i32(), coordinates.i32(),
destination
); );
let pool = AsyncComputeTaskPool::get(); let pool = AsyncComputeTaskPool::get();
let task = pool.spawn(async move { let task = pool.spawn(async move {
@ -247,10 +238,10 @@ fn poll_tasks(mut commands: Commands, mut query: Query<(Entity, &mut Calculating
for (entity, mut calculating) in query.iter_mut() { for (entity, mut calculating) in query.iter_mut() {
if let Some(result) = future::block_on(future::poll_once(&mut **calculating)) { if let Some(result) = future::block_on(future::poll_once(&mut **calculating)) {
if let Some(path) = result { if let Some(path) = result {
trace!("{entity:?}: Path: {path:?}"); trace!("{:?}: path: result: {:?}", entity, path);
commands.entity(entity).insert(path); commands.entity(entity).insert(path);
} else { } else {
trace!("{entity:?}: path: no path"); trace!("{:?}: path: no path", entity);
commands.entity(entity).insert(NoPath); commands.entity(entity).insert(NoPath);
} }
commands.entity(entity).remove::<Calculating>(); commands.entity(entity).remove::<Calculating>();
@ -277,74 +268,53 @@ fn negotiate_path(
&mut ActionState<NavigationAction>, &mut ActionState<NavigationAction>,
&mut Path, &mut Path,
&mut Transform, &mut Transform,
&Collider,
Option<&RotationSpeed>, Option<&RotationSpeed>,
)>, )>,
rapier_context: Res<RapierContext>,
) { ) {
for (entity, mut actions, mut path, mut transform, collider, rotation_speed) in &mut query { for (entity, mut actions, mut path, mut transform, rotation_speed) in &mut query {
let start_i32 = transform.translation.truncate().i32(); let start_i32 = (transform.translation.x, transform.translation.y).i32();
trace!( trace!(
"{entity:?}: start pathfinding from {start_i32:?} to {:?}: {:?}", "{entity:?}: start pathfinding from {start_i32:?} to {:?}: {:?}",
path.last(), path.last(),
transform.translation.truncate() transform.translation.truncate()
); );
if path.len() > 0 { let mut cleanup = false;
if path.len() > 1 && path[0] != start_i32 && path[1] != start_i32 { if let Some(last) = path.last() {
trace!("Off path"); if last == &start_i32 {
} else if path.len() > 1 && path[1] == start_i32 { trace!("{entity:?}: path: at destination");
trace!("Next in path is start of path, shouldn't happen"); cleanup = true;
}
if path[0] == start_i32 {
trace!("At start, removing");
path.remove(0);
} }
} }
if let Some(next) = path.first() { if !cleanup {
trace!("{entity:?}: path: moving from {start_i32:?} to {next:?}"); if let Some(position) = path.iter().position(|v| v == &start_i32) {
let start = transform.translation.truncate(); trace!("{entity:?}: Path contains start");
let mut next = Vec2::new(next.0 as f32, next.1 as f32); let (_, new_path) = path.split_at(position + 1);
if next.x > 0. { **path = new_path.to_vec();
next.x += 0.5; }
if let Some(next) = path.first() {
trace!("{entity:?}: path: moving from {start_i32:?} to {next:?}");
let start = Vec2::new(start_i32.x(), start_i32.y());
let next = Vec2::new(next.0 as f32, next.1 as f32);
let mut direction = next - start;
direction = direction.normalize();
trace!("{entity:?}: path: direction: {direction:?}");
actions.press(NavigationAction::Move);
actions.action_data_mut(NavigationAction::Move).axis_pair =
Some(DualAxisData::from_xy(Vec2::new(-direction.y, direction.x)));
trace!(
"{entity:?}: path: move: {:?}",
Vec2::new(direction.y, -direction.x)
);
if rotation_speed.is_some() {
let angle = direction.y.atan2(direction.x);
transform.rotation = Quat::from_rotation_z(angle);
}
} else { } else {
next -= 0.5; trace!("{entity:?}: empty path, cleaning");
cleanup = true;
} }
if next.y > 0. { }
next.y += 0.5; if cleanup {
} else {
next.y -= 0.5;
}
let mut direction = next - start;
direction = direction.normalize();
trace!(
"{entity:?}: Direction: {direction:?}, Distance: {}",
(next - start).length()
);
if let Some((hit, toi)) = rapier_context.cast_shape(
start,
transform.yaw().radians(),
direction,
&*collider,
rapier_context.integration_parameters.dt,
QueryFilter::new()
.exclude_sensors()
.exclude_collider(entity),
) {
trace!("{entity:?} is stuck, hit: {hit:?}, TOI: {toi:?}");
// TODO: Remove when we have an actual character controller.
transform.translation = next.extend(0.);
continue;
}
trace!("{entity:?}: path: direction: {direction:?}");
actions.press(NavigationAction::Move);
actions.action_data_mut(NavigationAction::Move).axis_pair =
Some(DualAxisData::from_xy(Vec2::new(-direction.y, direction.x)));
if rotation_speed.is_some() {
let angle = direction.y.atan2(direction.x);
transform.rotation = Quat::from_rotation_z(angle);
}
} else {
trace!("{entity:?}: empty path, cleaning");
commands commands
.entity(entity) .entity(entity)
.remove::<Path>() .remove::<Path>()
@ -360,41 +330,24 @@ fn actions(
mut commands: Commands, mut commands: Commands,
mut query: Query<( mut query: Query<(
Entity, Entity,
&mut ActionState<NegotiatePathAction>, &ActionState<NegotiatePathAction>,
&mut ActionState<NavigationAction>,
Option<&mut Destination>, Option<&mut Destination>,
)>, )>,
) { ) {
for (entity, mut actions, mut navigation_action, destination) in &mut query { for (entity, actions, destination) in &mut query {
if actions.pressed(NegotiatePathAction) { if actions.pressed(NegotiatePathAction) {
if let Some(pair) = actions.axis_pair(NegotiatePathAction) { if let Some(pair) = actions.axis_pair(NegotiatePathAction) {
trace!("Negotiating path to {pair:?}");
let dest = Destination((pair.x() as i32, pair.y() as i32)); let dest = Destination((pair.x() as i32, pair.y() as i32));
if let Some(mut current_dest) = destination { if let Some(mut current_dest) = destination {
if *current_dest != dest { if *current_dest != dest {
trace!("{entity:?}: New destination, zeroing velocity");
navigation_action.press(NavigationAction::SetLinearVelocity);
navigation_action
.action_data_mut(NavigationAction::SetLinearVelocity)
.axis_pair = Some(DualAxisData::from_xy(Vec2::ZERO));
*current_dest = dest; *current_dest = dest;
} }
} else { } else {
trace!("{entity:?}: Adding destination, zeroing velocity");
navigation_action.press(NavigationAction::SetLinearVelocity);
navigation_action
.action_data_mut(NavigationAction::SetLinearVelocity)
.axis_pair = Some(DualAxisData::from_xy(Vec2::ZERO));
commands.entity(entity).insert(dest); commands.entity(entity).insert(dest);
} }
} else if destination.is_some() { } else if destination.is_some() {
commands commands.entity(entity).remove::<Destination>();
.entity(entity)
.remove::<Destination>()
.remove::<NoPath>();
} }
actions.release(NegotiatePathAction);
actions.action_data_mut(NegotiatePathAction).axis_pair = None;
} }
} }
} }
@ -408,18 +361,13 @@ impl Plugin for PathfindingPlugin {
.register_type::<NoPath>() .register_type::<NoPath>()
.register_type::<Path>() .register_type::<Path>()
.register_type::<CostMap>() .register_type::<CostMap>()
.add_system_to_stage(CoreStage::PreUpdate, calculate_path) .add_system(calculate_path)
.add_system_to_stage(CoreStage::PostUpdate, remove_destination) .add_system_to_stage(CoreStage::PostUpdate, remove_destination)
.add_system_to_stage(CoreStage::PreUpdate, poll_tasks) .add_system(poll_tasks)
.add_system_to_stage( .add_system_to_stage(
CoreStage::PreUpdate, CoreStage::PreUpdate,
negotiate_path.after(InputManagerSystem::Tick), negotiate_path.after(InputManagerSystem::Tick),
) )
.add_system_to_stage( .add_system(actions);
CoreStage::PreUpdate,
actions
.after(InputManagerSystem::Update)
.before(calculate_path),
);
} }
} }