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| {
matches!(
cs,
comp::CharacterState::GlideWield | comp::CharacterState::Glide(_)
comp::CharacterState::GlideWield(_) | comp::CharacterState::Glide(_)
)
});

View File

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

View File

@ -1,4 +1,4 @@
use super::utils::handle_climb;
use super::{glide_wield, utils::handle_climb};
use crate::{
comp::{inventory::slot::EquipSlot, CharacterState, ControllerInputs, Ori, StateUpdate, Vel},
glider::Glider,
@ -108,7 +108,7 @@ impl CharacterBehavior for Data {
if data.physics.on_ground
&& (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();
} else if data.physics.in_liquid().is_some()
|| data.inventory.equipped(EquipSlot::Glider).is_none()
@ -149,9 +149,6 @@ impl CharacterBehavior for Data {
{
let glider_up = glider.ori.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 (d - max_roll.cos()).is_sign_positive()

View File

@ -1,14 +1,26 @@
use super::utils::*;
use crate::{
comp::{slot::EquipSlot, CharacterState, InventoryAction, StateUpdate},
comp::{slot::EquipSlot, Body, CharacterState, InventoryAction, Ori, StateUpdate},
glider::Glider,
states::{
behavior::{CharacterBehavior, JoinData},
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 {
fn behavior(&self, data: &JoinData) -> StateUpdate {
@ -20,25 +32,26 @@ impl CharacterBehavior for Data {
handle_dodge_input(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 !data.physics.on_ground {
let glider = Glider::new(
data.body.dimensions().z * 3.0,
data.body.dimensions().z / 3.0,
*data.ori,
);
update.character = CharacterState::Glide(glide::Data::new(glider, data.ori));
}
if data
update.character = if !data.physics.on_ground {
CharacterState::Glide(glide::Data::new(glider, data.ori))
} else if data
.physics
.in_liquid()
.map(|depth| depth > 0.5)
.unwrap_or(false)
{
update.character = CharacterState::Idle;
}
if data.inventory.equipped(EquipSlot::Glider).is_none() {
update.character = CharacterState::Idle
CharacterState::Idle
} else if data.inventory.equipped(EquipSlot::Glider).is_none() {
CharacterState::Idle
} else {
CharacterState::GlideWield(Self(glider))
};
update

View File

@ -570,7 +570,7 @@ pub fn attempt_glide_wield(data: &JoinData, update: &mut StateUpdate) {
.unwrap_or(false)
&& 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::Climb(data) => data.handle_event(&j, action),
CharacterState::Glide(data) => data.handle_event(&j, action),
CharacterState::GlideWield => {
states::glide_wield::Data.handle_event(&j, action)
CharacterState::GlideWield(data) => {
data.handle_event(&j, action)
},
CharacterState::Stunned(data) => data.handle_event(&j, action),
CharacterState::Sit => {
@ -360,7 +360,7 @@ impl<'a> System<'a> for Sys {
CharacterState::Talk => states::talk::Data.behavior(&j),
CharacterState::Climb(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::Sit => states::sit::Data::behavior(&states::sit::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,
) -> Option<()> {
let glider = match character_state {
CharacterState::Glide(glider) => Some(glider.glider),
CharacterState::Glide(data) => Some(data.glider),
CharacterState::GlideWield(data) => Some(data.0),
_ => None,
}?;

View File

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

View File

@ -5,8 +5,9 @@ use super::{
pub struct GlideWieldAnimation;
type GlideWieldAnimationDependency = (Quaternion<f32>, Quaternion<f32>);
impl Animation for GlideWieldAnimation {
type Dependency<'a> = ();
type Dependency<'a> = GlideWieldAnimationDependency;
type Skeleton = CharacterSkeleton;
#[cfg(feature = "use-dyn-lib")]
@ -16,21 +17,25 @@ impl Animation for GlideWieldAnimation {
fn update_skeleton_inner<'a>(
skeleton: &Self::Skeleton,
_: Self::Dependency<'a>,
(orientation, glider_orientation): Self::Dependency<'a>,
_anim_time: f32,
rate: &mut f32,
s_a: &SkeletonAttr,
) -> Self::Skeleton {
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;
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_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.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);

View File

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