Improve glider rotation

This commit is contained in:
Ludvig Böklin 2021-06-09 13:57:18 +02:00
parent 29b0aafdad
commit a23a2a7b92

View File

@ -3,7 +3,7 @@ use crate::{
comp::{inventory::slot::EquipSlot, CharacterState, ControllerInputs, Ori, StateUpdate, Vel}, comp::{inventory::slot::EquipSlot, CharacterState, ControllerInputs, Ori, StateUpdate, Vel},
glider::Glider, glider::Glider,
states::behavior::{CharacterBehavior, JoinData}, states::behavior::{CharacterBehavior, JoinData},
util::Dir, util::{Dir, Plane, Projection},
}; };
use inline_tweak::tweak; use inline_tweak::tweak;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -60,16 +60,19 @@ impl Data {
} }
} }
fn tgt_up(&self, max_roll: f32, tgt_dir: &Dir, flow_dir: &Dir, data: &JoinData) -> Dir { fn roll_dir(&self, max_roll: f32, tgt_dir: &Dir, flow_dir: &Dir, data: &JoinData) -> Dir {
let char_up = data.ori.up(); let char_up = data.ori.up();
Dir::from_unnormalized(tgt_dir.to_vec() + flow_dir.to_vec()) Dir::from_unnormalized(tgt_dir.to_vec() + flow_dir.to_vec())
.map(|tgt_lift_dir| { .map(|tgt_lift_dir| {
// this rolls to decrease the surface exposed to unfavourable wind that is
// causing us to drift off course
tgt_lift_dir.slerped_to( tgt_lift_dir.slerped_to(
-*flow_dir, -*flow_dir,
Dir::from_unnormalized(data.vel.0) Dir::from_unnormalized(data.vel.0)
.map_or(0.0, |moving_dir| moving_dir.dot(flow_dir.to_vec()).max(0.0)), .map_or(0.0, |moving_dir| moving_dir.dot(flow_dir.to_vec()).max(0.0)),
) )
}) })
.and_then(|dir| dir.projected(&Plane::from(data.ori.look_dir())))
.and_then(|dir| { .and_then(|dir| {
(dir.dot(*char_up) > max_roll.cos()) (dir.dot(*char_up) > max_roll.cos())
.then_some(dir) .then_some(dir)
@ -79,7 +82,6 @@ impl Data {
.try_normalized() .try_normalized()
.map(|axis| Quaternion::rotation_3d(max_roll, axis) * char_up) .map(|axis| Quaternion::rotation_3d(max_roll, axis) * char_up)
}) })
.filter(|dir| dir.dot(*self.glider.ori.up()).is_sign_positive())
}) })
.unwrap_or(char_up) .unwrap_or(char_up)
} }
@ -101,11 +103,11 @@ impl CharacterBehavior for Data {
} else if !handle_climb(&data, &mut update) { } else if !handle_climb(&data, &mut update) {
// Tweaks // Tweaks
let base_pitch = BASE_PITCH * tweak!(1.0); let base_pitch = BASE_PITCH * tweak!(1.0);
let max_pitch = tweak!(0.3) * PI; let max_pitch = tweak!(0.2) * PI;
let max_roll = tweak!(0.2) * PI; let max_roll = tweak!(0.5) * PI;
let inputs_rate = tweak!(5.0); let inputs_rate = tweak!(5.0);
let look_pitch_rate = tweak!(10.0); let look_pitch_rate = tweak!(5.0);
let autoroll_rate = tweak!(10.0); let autoroll_rate = tweak!(5.0);
let yaw_correction_rate = tweak!(1.0); let yaw_correction_rate = tweak!(1.0);
let char_yaw_follow_rate = tweak!(2.0); let char_yaw_follow_rate = tweak!(2.0);
// ---- // ----
@ -118,39 +120,42 @@ impl CharacterBehavior for Data {
let flow_dir = Dir::from_unnormalized(air_flow.0).unwrap_or_else(Dir::up); let flow_dir = Dir::from_unnormalized(air_flow.0).unwrap_or_else(Dir::up);
let tgt_dir = self.tgt_dir(base_pitch, max_pitch, data); let tgt_dir = self.tgt_dir(base_pitch, max_pitch, data);
let char_up = data.ori.up();
let ori = self.glider.ori; let ori = self.glider.ori;
let mut glider = self.glider; let mut glider = self.glider;
{ {
let char_fw = data.ori.look_dir();
let char_up = data.ori.up();
let glider_up = ori.up(); let glider_up = ori.up();
let up_dot = glider_up.dot(*char_up); let glider_right = ori.right();
let mut next_up = glider_up;
if let Some(roll_input) = self.roll_input(data.inputs) { if let Some(roll_input) = self.roll_input(data.inputs) {
if (up_dot - max_roll.cos()).is_sign_positive() next_up = next_up.slerped_to(
|| (ori.right().dot(*char_up).is_sign_positive() Quaternion::rotation_3d(roll_input * max_roll, char_fw) * char_up,
== roll_input.is_sign_positive()) data.dt.0 * inputs_rate,
{
glider.roll(data.dt.0 * inputs_rate * roll_input * max_roll);
}
} else {
let tgt_up = self.tgt_up(max_roll, &tgt_dir, &flow_dir, data);
glider.slerp_roll_towards(
tgt_up,
autoroll_rate * (1.0 - tgt_up.dot(*glider_up).max(0.0).powi(2)) * data.dt.0,
); );
} else {
let roll_dir = self.roll_dir(max_roll, &tgt_dir, &flow_dir, data);
let s = 1.0 - roll_dir.dot(*glider_up).abs();
next_up = next_up.slerped_to(roll_dir, data.dt.0 * autoroll_rate * s);
} }
if let Some(pitch_input) = self.pitch_input(data.inputs) { if let Some(pitch_input) = self.pitch_input(data.inputs) {
if (up_dot - max_pitch.cos()).is_sign_positive() next_up = next_up.slerped_to(
|| (ori.look_dir().dot(*char_up).is_sign_negative() Quaternion::rotation_3d(pitch_input * max_pitch, glider_right) * char_up,
== pitch_input.is_sign_positive()) data.dt.0 * inputs_rate,
{ );
glider.pitch(data.dt.0 * inputs_rate * pitch_input * max_pitch); } else {
} // slerp un-pitching for more stable rolling
let tgt_fw = tgt_dir.slerped_to(char_fw, tgt_dir.dot(*glider_right).powi(2));
next_up = next_up.slerped_to(
data.ori.pitched_towards(tgt_fw).up(),
data.dt.0 * look_pitch_rate,
);
} }
glider.slerp_pitch_towards(tgt_dir, look_pitch_rate * data.dt.0);
glider.ori = ori.prerotated(glider_up.rotation_between(next_up));
} }
glider.slerp_yaw_towards(-flow_dir, data.dt.0 * yaw_correction_rate); glider.slerp_yaw_towards(-flow_dir, data.dt.0 * yaw_correction_rate);