diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 883740ee51..67e77ff275 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -452,6 +452,24 @@ pub fn handle_orientation( efficiency: f32, dir_override: Option, ) { + /// first check for horizontal + fn to_horizontal_fast(ori: &crate::comp::Ori) -> crate::comp::Ori { + if ori.to_quat().into_vec4().xy().is_approx_zero() { + // if ori.to_horizontal().dot(*ori) < (1.0 - 4.0 * f32::EPSILON) { + // tracing::error!("{:?} {}", ori, ori.to_horizontal().dot(*ori)); + // } + // debug_assert!(ori.to_horizontal().dot(*ori) >= (1.0 - 4.0 * f32::EPSILON)); + *ori + } else { + //tracing::info!("non horizontal {:?}", ori); + ori.to_horizontal() + } + } + /// compute an upper limit for the difference of two orientations + fn ori_absdiff(a: &crate::comp::Ori, b: &crate::comp::Ori) -> f32 { + (a.to_quat().into_vec4() - b.to_quat().into_vec4()).reduce(|a, b| a.abs() + b.abs()) + } + // Direction is set to the override if one is provided, else if entity is // strafing or attacking the horiontal component of the look direction is used, // else the current horizontal movement direction is used @@ -465,24 +483,74 @@ pub fn handle_orientation( .into() } else { Dir::from_unnormalized(data.inputs.move_dir.into()) - .map_or_else(|| data.ori.to_horizontal(), |dir| dir.into()) + .map_or_else(|| to_horizontal_fast(data.ori), |dir| dir.into()) }; - let rate = { - // Angle factor used to keep turning rate approximately constant by - // counteracting slerp turning more with a larger angle - let angle_factor = 2.0 / (1.0 - update.ori.dot(target_ori)).sqrt(); - data.body.base_ori_rate() - * efficiency - * angle_factor - * if data.physics.on_ground.is_some() { - 1.0 - } else { - 0.2 - } + // unit is multiples of 180° + let half_turns_per_tick = data.body.base_ori_rate() + * efficiency + * if data.physics.on_ground.is_some() { + 1.0 + } else { + 0.2 + } + * data.dt.0; + // very rough guess + let ticks_from_target_guess = ori_absdiff(&update.ori, &target_ori) / half_turns_per_tick; + let instantaneous = ticks_from_target_guess < 1.0; + update.ori = if instantaneous { + // if (half_turns_per_tick * 2.0 / (1.0 - update.ori.dot(target_ori)).sqrt()) < + // 1.0 { tracing::error!( + // "{:?} {} {} {:?} {:?} {:?} {:?} {}", + // data.body.mass(), + // data.body.base_ori_rate(), + // update.ori.dot(target_ori), + // update.ori.look_dir(), + // target_ori.look_dir(), + // update.ori, + // target_ori, + // ticks_from_target_guess + // ); + // tracing::error!( + // "{} {} {}", + // half_turns_per_tick, + // 2.0 / (1.0 - update.ori.dot(target_ori)).sqrt(), + // update.ori.angle_between(target_ori) * 180.0 / std::f32::consts::PI, + // ); + // } + // debug_assert!( + // (half_turns_per_tick * 2.0 / (1.0 - update.ori.dot(target_ori)).sqrt()) + // >= 1.0 ); + target_ori + } else { + // tracing::trace!( + // "{} {} {} {:?} {} {:?} {:?}", + // update.ori.dot(target_ori), + // ticks_from_target_guess, + // half_turns_per_tick, + // data.body.mass(), + // data.body.base_ori_rate(), + // update.ori, + // target_ori, + // ); + let target_fraction = { + // Angle factor used to keep turning rate approximately constant by + // counteracting slerp turning more with a larger angle + let angle_factor = 2.0 / (1.0 - update.ori.dot(target_ori)).sqrt(); + + half_turns_per_tick * angle_factor + }; + //let res = + update + .ori + .slerped_towards(target_ori, target_fraction.min(1.0)) + // tracing::trace!( + // ">>{}<< {} {}", + // target_fraction, + // data.dt.0, + // res.dot(target_ori) + // ); + //res }; - update.ori = update - .ori - .slerped_towards(target_ori, (data.dt.0 * rate).min(1.0)); } /// Updates components to move player as if theyre swimming