mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Improve gliding
- make glider dimensions a factor of body height - increase glider dimensions across the board - remove delay from transition into glide - enable glider control while wielding glider - improve glide wield animation
This commit is contained in:
parent
b667ba86f9
commit
ebf489984c
@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- NPCs can now warn players before engaging in combat
|
||||
- Custom error message when a supported graphics backend can not be found
|
||||
- Add server setting with PvE/PvP switch
|
||||
- Can now tilt glider while only wielding it
|
||||
|
||||
### Changed
|
||||
|
||||
@ -47,6 +48,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- The types of animals that can be tamed as pets are now limited to certain species, pending further balancing of pets
|
||||
- Made server-cli admin add/remove command use positional arguments again
|
||||
- Usage of "stamina" replaced with "energy"
|
||||
- Glider dimensions now depend on character height
|
||||
- Glider dimensions somewhat increased overall
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -194,6 +194,30 @@ impl Ori {
|
||||
self.rotated(Quaternion::rotation_y(angle_radians))
|
||||
}
|
||||
|
||||
/// Returns a version which is rolled such that its up points towards `dir`
|
||||
/// as much as possible without pitching or yawing
|
||||
pub fn rolled_towards(self, dir: Dir) -> Self {
|
||||
dir.projected(&Plane::from(self.look_dir()))
|
||||
.map_or(self, |dir| self.prerotated(self.up().rotation_between(dir)))
|
||||
}
|
||||
|
||||
/// Returns a version which has been pitched towards `dir` as much as
|
||||
/// possible without yawing or rolling
|
||||
pub fn pitched_towards(self, dir: Dir) -> Self {
|
||||
dir.projected(&Plane::from(self.right()))
|
||||
.map_or(self, |dir_| {
|
||||
self.prerotated(self.look_dir().rotation_between(dir_))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a version which has been yawed towards `dir` as much as possible
|
||||
/// without pitching or rolling
|
||||
pub fn yawed_towards(self, dir: Dir) -> Self {
|
||||
dir.projected(&Plane::from(self.up())).map_or(self, |dir_| {
|
||||
self.prerotated(self.look_dir().rotation_between(dir_))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a version without sideways tilt (roll)
|
||||
///
|
||||
/// ```
|
||||
|
@ -80,7 +80,7 @@ impl CharacterBehavior for Data {
|
||||
if data.physics.on_ground.is_some()
|
||||
&& (data.vel.0 - data.physics.ground_vel).magnitude_squared() < 2_f32.powi(2)
|
||||
{
|
||||
update.character = CharacterState::GlideWield(glide_wield::Data::default());
|
||||
update.character = CharacterState::GlideWield(glide_wield::Data::from(data));
|
||||
} else if data.physics.in_liquid().is_some()
|
||||
|| data
|
||||
.inventory
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{slot::EquipSlot, CharacterState, InventoryAction, StateUpdate},
|
||||
comp::{slot::EquipSlot, CharacterState, InventoryAction, Ori, StateUpdate},
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
glide,
|
||||
@ -10,13 +10,25 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
// time since left ground, for preventing state transition
|
||||
// before block snapping kicks in
|
||||
timer: f32,
|
||||
pub ori: Ori,
|
||||
span_length: f32,
|
||||
chord_length: f32,
|
||||
}
|
||||
|
||||
impl Default for Data {
|
||||
fn default() -> Self { Self { timer: 0.0 } }
|
||||
impl From<&JoinData<'_>> for Data {
|
||||
fn from(data: &JoinData) -> Self {
|
||||
let scale = data.body.dimensions().z;
|
||||
Self {
|
||||
// Aspect ratio is what really matters for lift/drag ratio
|
||||
// and the aerodynamics model works for ARs up to 25.
|
||||
// The inflated dimensions are hopefully only a temporary
|
||||
// bandaid for the poor glide ratio experienced under 2.5G.
|
||||
// A span/chord ratio of 4.5 gives an AR of ~5.73.
|
||||
span_length: scale * 3.0,
|
||||
chord_length: scale / 1.5,
|
||||
ori: *data.ori,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
@ -29,31 +41,37 @@ impl CharacterBehavior for Data {
|
||||
handle_dodge_input(data, &mut update);
|
||||
handle_wield(data, &mut update);
|
||||
|
||||
// If still in this state, do the things
|
||||
if matches!(update.character, CharacterState::GlideWield(_)) {
|
||||
// If not on the ground while wielding glider enter gliding state
|
||||
if data.physics.on_ground.is_none() {
|
||||
update.character = if self.timer > 0.3 {
|
||||
CharacterState::Glide(glide::Data::new(10.0, 0.6, *data.ori))
|
||||
} else {
|
||||
CharacterState::GlideWield(Self {
|
||||
timer: self.timer + data.dt.0,
|
||||
})
|
||||
};
|
||||
}
|
||||
if data
|
||||
.physics
|
||||
.in_liquid()
|
||||
.map(|depth| depth > 0.5)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
update.character = CharacterState::Idle;
|
||||
}
|
||||
if data
|
||||
update.character = if data.physics.on_ground.is_none() {
|
||||
CharacterState::Glide(glide::Data::new(
|
||||
self.span_length,
|
||||
self.chord_length,
|
||||
self.ori,
|
||||
))
|
||||
// make sure we have a glider and we're not (too deep) in water
|
||||
} else if data
|
||||
.inventory
|
||||
.and_then(|inv| inv.equipped(EquipSlot::Glider))
|
||||
.is_none()
|
||||
.is_some()
|
||||
&& data.physics.in_liquid().map_or(true, |depth| depth < 0.5)
|
||||
{
|
||||
update.character = CharacterState::Idle
|
||||
CharacterState::GlideWield(Self {
|
||||
// Glider tilt follows look dir
|
||||
ori: self.ori.slerped_towards(
|
||||
data.ori.slerped_towards(
|
||||
Ori::from(data.inputs.look_dir).pitched_up(0.6),
|
||||
(1.0 + data.inputs.look_dir.dot(*data.ori.look_dir()).max(0.0)) / 3.0,
|
||||
),
|
||||
5.0 * data.dt.0,
|
||||
),
|
||||
..*self
|
||||
})
|
||||
} else {
|
||||
CharacterState::Idle
|
||||
};
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -638,7 +638,7 @@ pub fn attempt_glide_wield(data: &JoinData<'_>, update: &mut StateUpdate) {
|
||||
.unwrap_or(false)
|
||||
&& data.body.is_humanoid()
|
||||
{
|
||||
update.character = CharacterState::GlideWield(glide_wield::Data::default());
|
||||
update.character = CharacterState::GlideWield(glide_wield::Data::from(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -1572,10 +1572,10 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::GlideWield { .. } => {
|
||||
CharacterState::GlideWield(data) => {
|
||||
anim::character::GlideWieldAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(),
|
||||
(ori, data.ori.into()),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
|
Loading…
Reference in New Issue
Block a user