mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Improve glider handling
This commit is contained in:
parent
0f6f7a9096
commit
91a8b19863
@ -1,10 +1,14 @@
|
|||||||
use super::utils::handle_climb;
|
use super::utils::handle_climb;
|
||||||
use crate::{
|
use crate::{
|
||||||
comp::{inventory::slot::EquipSlot, CharacterState, Ori, StateUpdate},
|
comp::{
|
||||||
|
fluid_dynamics::angle_of_attack, inventory::slot::EquipSlot, CharacterState, Ori,
|
||||||
|
StateUpdate,
|
||||||
|
},
|
||||||
states::behavior::{CharacterBehavior, JoinData},
|
states::behavior::{CharacterBehavior, JoinData},
|
||||||
util::Dir,
|
util::{Dir, Plane, Projection},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::f32::consts::PI;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -24,7 +28,7 @@ impl Data {
|
|||||||
///
|
///
|
||||||
/// https://en.wikipedia.org/wiki/Elliptical_wing
|
/// https://en.wikipedia.org/wiki/Elliptical_wing
|
||||||
pub fn new(span_length: f32, chord_length: f32, ori: Ori) -> Self {
|
pub fn new(span_length: f32, chord_length: f32, ori: Ori) -> Self {
|
||||||
let planform_area = std::f32::consts::PI * chord_length * span_length * 0.25;
|
let planform_area = PI * chord_length * span_length * 0.25;
|
||||||
Self {
|
Self {
|
||||||
aspect_ratio: span_length.powi(2) / planform_area,
|
aspect_ratio: span_length.powi(2) / planform_area,
|
||||||
planform_area,
|
planform_area,
|
||||||
@ -53,53 +57,54 @@ impl CharacterBehavior for Data {
|
|||||||
} else if handle_climb(&data, &mut update) {
|
} else if handle_climb(&data, &mut update) {
|
||||||
update
|
update
|
||||||
} else {
|
} else {
|
||||||
let tgt_ori = Some(data.inputs.move_dir)
|
let slerp_s = {
|
||||||
|
let angle = self.ori.look_dir().angle_between(*data.inputs.look_dir);
|
||||||
|
let rate = 0.4 * PI / angle;
|
||||||
|
(data.dt.0 * rate).min(0.1)
|
||||||
|
};
|
||||||
|
|
||||||
|
let ori = Some(data.inputs.move_dir)
|
||||||
.filter(|mv_dir| !mv_dir.is_approx_zero())
|
.filter(|mv_dir| !mv_dir.is_approx_zero())
|
||||||
.map(|mv_dir| {
|
.or_else(|| self.ori.look_dir().xy().try_normalized())
|
||||||
Vec3::new(
|
.map(|mv_dir| Vec3::new(mv_dir.x, mv_dir.y, (data.inputs.look_dir.z + 0.3) * 2.0))
|
||||||
mv_dir.x,
|
|
||||||
mv_dir.y,
|
|
||||||
Lerp::lerp_unclamped(
|
|
||||||
0.0,
|
|
||||||
data.inputs.look_dir.z + 0.3,
|
|
||||||
mv_dir.magnitude_squared() * 2.0,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.and_then(Dir::from_unnormalized)
|
.and_then(Dir::from_unnormalized)
|
||||||
.and_then(|tgt_dir| {
|
.and_then(|tgt_dir| {
|
||||||
Dir::from_unnormalized(data.vel.0)
|
data.physics
|
||||||
.and_then(|moving_dir| moving_dir.to_horizontal())
|
.in_fluid
|
||||||
.or_else(|| self.ori.look_dir().to_horizontal())
|
.map(|fluid| fluid.relative_flow(data.vel))
|
||||||
.map(|moving_dir| {
|
.and_then(|air_flow| {
|
||||||
Ori::from(tgt_dir).rolled_right(
|
let flow_dir = Dir::from_unnormalized(air_flow.0)?;
|
||||||
(1.0 - moving_dir.dot(*tgt_dir).max(0.0))
|
let tgt_dir_ori = Ori::from(tgt_dir);
|
||||||
* self.ori.right().dot(*tgt_dir).signum()
|
let tgt_dir_up = tgt_dir_ori.up();
|
||||||
* std::f32::consts::PI
|
let tgt_up = flow_dir.projected(&Plane::from(tgt_dir)).map(|d| {
|
||||||
/ 3.0,
|
let ddot = d.dot(*tgt_dir_up);
|
||||||
|
if ddot.is_sign_negative() {
|
||||||
|
Quaternion::rotation_3d(PI, *tgt_dir_ori.right()) * d
|
||||||
|
} else {
|
||||||
|
d
|
||||||
|
}
|
||||||
|
.slerped_to(tgt_dir_up, 0.25 * ddot.abs().powf(0.25))
|
||||||
|
})?;
|
||||||
|
let global_roll = tgt_dir_up.rotation_between(tgt_up);
|
||||||
|
Some(
|
||||||
|
tgt_dir_ori
|
||||||
|
.prerotated(global_roll)
|
||||||
|
.pitched_up(angle_of_attack(&tgt_dir_ori, &flow_dir)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| self.ori.uprighted());
|
.map(|tgt_ori| self.ori.slerped_towards(tgt_ori, slerp_s))
|
||||||
|
.unwrap_or_else(|| self.ori.slerped_towards(self.ori.uprighted(), slerp_s));
|
||||||
|
|
||||||
let rate = {
|
|
||||||
let angle = self.ori.look_dir().angle_between(*data.inputs.look_dir);
|
|
||||||
0.4 * std::f32::consts::PI / angle
|
|
||||||
};
|
|
||||||
|
|
||||||
let ori = self
|
|
||||||
.ori
|
|
||||||
.slerped_towards(tgt_ori, (data.dt.0 * rate).min(0.1));
|
|
||||||
update.character = CharacterState::Glide(Self { ori, ..*self });
|
update.character = CharacterState::Glide(Self { ori, ..*self });
|
||||||
|
|
||||||
if let Some(char_ori) = ori.to_horizontal() {
|
if let Some(char_ori) = ori.to_horizontal() {
|
||||||
let rate = {
|
let slerp_s = {
|
||||||
let angle = ori.look_dir().angle_between(*data.inputs.look_dir);
|
let angle = ori.look_dir().angle_between(*data.inputs.look_dir);
|
||||||
data.body.base_ori_rate() * std::f32::consts::PI / angle
|
let rate = data.body.base_ori_rate() * PI / angle;
|
||||||
|
(data.dt.0 * rate).min(0.1)
|
||||||
};
|
};
|
||||||
update.ori = update
|
update.ori = update.ori.slerped_towards(char_ori, slerp_s);
|
||||||
.ori
|
|
||||||
.slerped_towards(char_ori, (data.dt.0 * rate).min(0.1));
|
|
||||||
}
|
}
|
||||||
update
|
update
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user