From 6cb677d3490c7a2a3882f2e034353b7b28d3cbc8 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Thu, 22 Aug 2024 01:07:28 +0200 Subject: [PATCH] Use shape cast for more accuracy --- examples/full_setup.rs | 2 +- src/interaction/hold/update.rs | 52 +++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/examples/full_setup.rs b/examples/full_setup.rs index dccc90a..310ac9c 100644 --- a/examples/full_setup.rs +++ b/examples/full_setup.rs @@ -11,7 +11,7 @@ fn main() { DefaultPlugins, WorldInspectorPlugin::new(), PhysicsPlugins::default(), - //PhysicsDebugPlugin::default(), + PhysicsDebugPlugin::default(), AvianPickupPlugin::default(), )) .add_systems(Startup, setup) diff --git a/src/interaction/hold/update.rs b/src/interaction/hold/update.rs index de5757f..1ceb5a6 100644 --- a/src/interaction/hold/update.rs +++ b/src/interaction/hold/update.rs @@ -133,19 +133,48 @@ pub(super) fn update_object( // actor's origins if possible instead. let max_distance = preferred_distance.max(min_distance); - let terrain_hit = spatial_query.cast_ray( + let Some(actor_space_rotation) = preferred_rotation + .map(|preferred| preferred.0) + .or_else(|| pre_pickup_rotation.map(|pre| pre.0)) + else { + error!("Held prop does not have a preferred or pre-pickup rotation. Ignoring."); + continue; + }; + // orient the prop wrt the actor + // The 2013 code uses the non-clamped code here, resulting in the prop + // rotating when looking further up than the clamp allows. + // Looks weird imo, so we use the clamped rotation. + let clamped_actor_transform = actor_transform.with_rotation(clamped_rotation); + let target_rotation = + prop_rotation_from_actor_space(actor_space_rotation, clamped_actor_transform); + + shadow.target_rotation = target_rotation; + + // The cast needs to be longer to account for the fact that + // the prop might hit terrain with the side that is not facing + // the player. We are assuming the prop has the same radius + // "behind" it as it has in front of it. Also add a bit of + // padding to be safe. + let max_cast_toi = max_distance + min_distance + 0.5; + + let terrain_hit = spatial_query.cast_shape( + &prop_collider, actor_transform.translation, + target_rotation, forward, - max_distance, + max_cast_toi, true, &config.terrain_filter, ); let distance = if let Some(terrain_hit) = terrain_hit { let fraction = terrain_hit.time_of_impact / max_distance; + info!("fraction: {}", fraction); if fraction < 0.5 { + info!("min distance"); min_distance } else { - max_distance + info!("far terrain hit"); + max_distance.min(terrain_hit.time_of_impact) } } else { max_distance @@ -155,23 +184,6 @@ pub(super) fn update_object( // distance let target_position = actor_transform.translation + forward * distance; shadow.target_position = target_position; - - let Some(actor_space_rotation) = preferred_rotation - .map(|preferred| preferred.0) - .or_else(|| pre_pickup_rotation.map(|pre| pre.0)) - else { - error!("Held prop does not have a preferred or pre-pickup rotation. Ignoring."); - continue; - }; - // orient the prop wrt the actor - // The 2013 code uses the non-clamped code here, resulting in the prop - // rotating when looking further up than the clamp allows. - // Looks weird imo, so we use the clamped rotation. - let clamped_actor_transform = actor_transform.with_rotation(clamped_rotation); - let target_rotation = - prop_rotation_from_actor_space(actor_space_rotation, clamped_actor_transform); - - shadow.target_rotation = target_rotation; } }