Implement aerodynamic GlideWield

This commit is contained in:
Ludvig Böklin 2021-06-04 13:59:42 +02:00
parent df666cef40
commit 9e20b090c4
10 changed files with 52 additions and 36 deletions

View File

@ -1252,7 +1252,7 @@ impl Client {
.map(|cs| { .map(|cs| {
matches!( matches!(
cs, cs,
comp::CharacterState::GlideWield | comp::CharacterState::Glide(_) comp::CharacterState::GlideWield(_) | comp::CharacterState::Glide(_)
) )
}); });

View File

@ -53,7 +53,7 @@ pub enum CharacterState {
Talk, Talk,
Sneak, Sneak,
Glide(glide::Data), Glide(glide::Data),
GlideWield, GlideWield(glide_wield::Data),
/// A stunned state /// A stunned state
Stunned(stunned::Data), Stunned(stunned::Data),
/// A basic blocking state /// A basic blocking state
@ -180,7 +180,7 @@ impl CharacterState {
| CharacterState::Equipping(_) | CharacterState::Equipping(_)
| CharacterState::Dance | CharacterState::Dance
| CharacterState::Glide(_) | CharacterState::Glide(_)
| CharacterState::GlideWield | CharacterState::GlideWield(_)
| CharacterState::Talk | CharacterState::Talk
| CharacterState::Roll(_), | CharacterState::Roll(_),
) )

View File

@ -1,4 +1,4 @@
use super::utils::handle_climb; use super::{glide_wield, utils::handle_climb};
use crate::{ use crate::{
comp::{inventory::slot::EquipSlot, CharacterState, ControllerInputs, Ori, StateUpdate, Vel}, comp::{inventory::slot::EquipSlot, CharacterState, ControllerInputs, Ori, StateUpdate, Vel},
glider::Glider, glider::Glider,
@ -108,7 +108,7 @@ impl CharacterBehavior for Data {
if data.physics.on_ground if data.physics.on_ground
&& (data.vel.0 - data.physics.ground_vel).magnitude_squared() < 2_f32.powi(2) && (data.vel.0 - data.physics.ground_vel).magnitude_squared() < 2_f32.powi(2)
{ {
update.character = CharacterState::GlideWield; update.character = CharacterState::GlideWield(glide_wield::Data(self.glider));
update.ori = update.ori.to_horizontal(); update.ori = update.ori.to_horizontal();
} else if data.physics.in_liquid().is_some() } else if data.physics.in_liquid().is_some()
|| data.inventory.equipped(EquipSlot::Glider).is_none() || data.inventory.equipped(EquipSlot::Glider).is_none()
@ -149,9 +149,6 @@ impl CharacterBehavior for Data {
{ {
let glider_up = glider.ori.up(); let glider_up = glider.ori.up();
let d = glider_up.dot(*char_up); let d = glider_up.dot(*char_up);
let cap = |max_ang: f32| -> Option<f32> {
(d - max_ang.cos()).is_sign_positive().then_some(max_ang)
};
if let Some(roll_input) = self.roll_input(data.inputs) { if let Some(roll_input) = self.roll_input(data.inputs) {
if (d - max_roll.cos()).is_sign_positive() if (d - max_roll.cos()).is_sign_positive()

View File

@ -1,14 +1,26 @@
use super::utils::*; use super::utils::*;
use crate::{ use crate::{
comp::{slot::EquipSlot, CharacterState, InventoryAction, StateUpdate}, comp::{slot::EquipSlot, Body, CharacterState, InventoryAction, Ori, StateUpdate},
glider::Glider, glider::Glider,
states::{ states::{
behavior::{CharacterBehavior, JoinData}, behavior::{CharacterBehavior, JoinData},
glide, glide,
}, },
}; };
use serde::{Deserialize, Serialize};
pub struct Data; #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Data(pub Glider);
impl Data {
pub fn new(body: &Body, ori: &Ori) -> Self {
Self(Glider::new(
body.dimensions().z * 3.0,
body.dimensions().z / 3.0,
*ori,
))
}
}
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {
@ -20,25 +32,26 @@ impl CharacterBehavior for Data {
handle_dodge_input(data, &mut update); handle_dodge_input(data, &mut update);
handle_wield(data, &mut update); handle_wield(data, &mut update);
let mut glider = self.0;
glider.ori = glider.ori.slerped_towards(
Ori::from(data.inputs.look_dir).pitched_up(inline_tweak::tweak!(0.35)),
inline_tweak::tweak!(10.0) * data.dt.0,
);
// If not on the ground while wielding glider enter gliding state // If not on the ground while wielding glider enter gliding state
if !data.physics.on_ground { update.character = if !data.physics.on_ground {
let glider = Glider::new( CharacterState::Glide(glide::Data::new(glider, data.ori))
data.body.dimensions().z * 3.0, } else if data
data.body.dimensions().z / 3.0,
*data.ori,
);
update.character = CharacterState::Glide(glide::Data::new(glider, data.ori));
}
if data
.physics .physics
.in_liquid() .in_liquid()
.map(|depth| depth > 0.5) .map(|depth| depth > 0.5)
.unwrap_or(false) .unwrap_or(false)
{ {
update.character = CharacterState::Idle; CharacterState::Idle
} } else if data.inventory.equipped(EquipSlot::Glider).is_none() {
if data.inventory.equipped(EquipSlot::Glider).is_none() { CharacterState::Idle
update.character = CharacterState::Idle } else {
CharacterState::GlideWield(Self(glider))
}; };
update update

View File

@ -570,7 +570,7 @@ pub fn attempt_glide_wield(data: &JoinData, update: &mut StateUpdate) {
.unwrap_or(false) .unwrap_or(false)
&& data.body.is_humanoid() && data.body.is_humanoid()
{ {
update.character = CharacterState::GlideWield; update.character = CharacterState::GlideWield(glide_wield::Data::new(data.body, data.ori));
} }
} }

View File

@ -297,8 +297,8 @@ impl<'a> System<'a> for Sys {
CharacterState::Talk => states::talk::Data.handle_event(&j, action), CharacterState::Talk => states::talk::Data.handle_event(&j, action),
CharacterState::Climb(data) => data.handle_event(&j, action), CharacterState::Climb(data) => data.handle_event(&j, action),
CharacterState::Glide(data) => data.handle_event(&j, action), CharacterState::Glide(data) => data.handle_event(&j, action),
CharacterState::GlideWield => { CharacterState::GlideWield(data) => {
states::glide_wield::Data.handle_event(&j, action) data.handle_event(&j, action)
}, },
CharacterState::Stunned(data) => data.handle_event(&j, action), CharacterState::Stunned(data) => data.handle_event(&j, action),
CharacterState::Sit => { CharacterState::Sit => {
@ -360,7 +360,7 @@ impl<'a> System<'a> for Sys {
CharacterState::Talk => states::talk::Data.behavior(&j), CharacterState::Talk => states::talk::Data.behavior(&j),
CharacterState::Climb(data) => data.behavior(&j), CharacterState::Climb(data) => data.behavior(&j),
CharacterState::Glide(data) => data.behavior(&j), CharacterState::Glide(data) => data.behavior(&j),
CharacterState::GlideWield => states::glide_wield::Data.behavior(&j), CharacterState::GlideWield(data) => data.behavior(&j),
CharacterState::Stunned(data) => data.behavior(&j), CharacterState::Stunned(data) => data.behavior(&j),
CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j), CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j),
CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, &j), CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, &j),

View File

@ -49,7 +49,8 @@ fn integrate_glider_forces(
rel_wind: &Vel, rel_wind: &Vel,
) -> Option<()> { ) -> Option<()> {
let glider = match character_state { let glider = match character_state {
CharacterState::Glide(glider) => Some(glider.glider), CharacterState::Glide(data) => Some(data.glider),
CharacterState::GlideWield(data) => Some(data.0),
_ => None, _ => None,
}?; }?;

View File

@ -279,7 +279,7 @@ impl<'a> System<'a> for Sys {
}); });
let is_gliding = matches!( let is_gliding = matches!(
read_data.char_states.get(entity), read_data.char_states.get(entity),
Some(CharacterState::GlideWield) | Some(CharacterState::Glide(_)) Some(CharacterState::GlideWield(_)) | Some(CharacterState::Glide(_))
) && !physics_state.on_ground; ) && !physics_state.on_ground;
if let Some(pid) = agent.position_pid_controller.as_mut() { if let Some(pid) = agent.position_pid_controller.as_mut() {

View File

@ -5,8 +5,9 @@ use super::{
pub struct GlideWieldAnimation; pub struct GlideWieldAnimation;
type GlideWieldAnimationDependency = (Quaternion<f32>, Quaternion<f32>);
impl Animation for GlideWieldAnimation { impl Animation for GlideWieldAnimation {
type Dependency<'a> = (); type Dependency<'a> = GlideWieldAnimationDependency;
type Skeleton = CharacterSkeleton; type Skeleton = CharacterSkeleton;
#[cfg(feature = "use-dyn-lib")] #[cfg(feature = "use-dyn-lib")]
@ -16,21 +17,25 @@ impl Animation for GlideWieldAnimation {
fn update_skeleton_inner<'a>( fn update_skeleton_inner<'a>(
skeleton: &Self::Skeleton, skeleton: &Self::Skeleton,
_: Self::Dependency<'a>, (orientation, glider_orientation): Self::Dependency<'a>,
_anim_time: f32, _anim_time: f32,
rate: &mut f32, rate: &mut f32,
s_a: &SkeletonAttr, s_a: &SkeletonAttr,
) -> Self::Skeleton { ) -> Self::Skeleton {
let mut next = (*skeleton).clone(); let mut next = (*skeleton).clone();
let glider_ori = orientation.inverse() * glider_orientation;
let glider_pos = Vec3::new(0.0, -5.0, 13.0);
*rate = 1.0; *rate = 1.0;
next.hand_l.position = Vec3::new(-2.0 - s_a.hand.0, s_a.hand.1, s_a.hand.2 + 15.0); next.hand_l.position =
glider_pos + glider_ori * Vec3::new(-s_a.hand.0 + -2.0, s_a.hand.1 + 8.0, s_a.hand.2);
next.hand_l.orientation = Quaternion::rotation_x(3.35) * Quaternion::rotation_y(0.2); next.hand_l.orientation = Quaternion::rotation_x(3.35) * Quaternion::rotation_y(0.2);
next.hand_r.position = Vec3::new(2.0 + s_a.hand.0, s_a.hand.1, s_a.hand.2 + 15.0); next.hand_r.position =
glider_pos + glider_ori * Vec3::new(s_a.hand.0 + 2.0, s_a.hand.1 + 8.0, s_a.hand.2);
next.hand_r.orientation = Quaternion::rotation_x(3.35) * Quaternion::rotation_y(-0.2); next.hand_r.orientation = Quaternion::rotation_x(3.35) * Quaternion::rotation_y(-0.2);
next.glider.scale = Vec3::one() * 1.0; next.glider.scale = Vec3::one() * 1.0;
next.glider.orientation = Quaternion::rotation_x(0.35); next.glider.orientation = glider_ori;
next.glider.position = Vec3::new(0.0, -5.0, 13.0); next.glider.position = Vec3::new(0.0, -5.0, 13.0);

View File

@ -1522,10 +1522,10 @@ impl FigureMgr {
skeleton_attr, skeleton_attr,
) )
}, },
CharacterState::GlideWield { .. } => { CharacterState::GlideWield(data) => {
anim::character::GlideWieldAnimation::update_skeleton( anim::character::GlideWieldAnimation::update_skeleton(
&target_base, &target_base,
(), (ori, data.0.ori.into()),
state.state_time, state.state_time,
&mut state_animation_rate, &mut state_animation_rate,
skeleton_attr, skeleton_attr,