From 63e500d3d8e9af1d97c506cd338a7da4f7193dff Mon Sep 17 00:00:00 2001 From: Isse Date: Sat, 14 Oct 2023 10:25:22 +0200 Subject: [PATCH] laying and steering animation --- assets/voxygen/i18n/en/hud/misc.ftl | 1 + common/src/comp/character_state.rs | 3 + common/src/terrain/sprite.rs | 25 +++--- common/systems/src/mount.rs | 10 ++- voxygen/anim/src/character/mod.rs | 10 ++- voxygen/anim/src/character/sleep.rs | 114 ++++++++++++++++++++++++++++ voxygen/anim/src/character/steer.rs | 110 +++++++++++++++++++++++++++ voxygen/src/hud/mod.rs | 1 + voxygen/src/scene/figure/mod.rs | 26 ++++++- 9 files changed, 277 insertions(+), 23 deletions(-) create mode 100644 voxygen/anim/src/character/sleep.rs create mode 100644 voxygen/anim/src/character/steer.rs diff --git a/assets/voxygen/i18n/en/hud/misc.ftl b/assets/voxygen/i18n/en/hud/misc.ftl index 7984a521fa..9f80fbb611 100644 --- a/assets/voxygen/i18n/en/hud/misc.ftl +++ b/assets/voxygen/i18n/en/hud/misc.ftl @@ -60,6 +60,7 @@ hud-follow = Follow hud-stay= Stay hud-sit = Sit hud-steer = Steer +hud-lay = Lay hud-portal = Portal -server = Server diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 60fdf33870..82c1930b9d 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -986,6 +986,9 @@ pub struct CharacterActivity { /// `None` means that the look direction should be derived from the /// orientation pub look_dir: Option, + /// If the character is using a Helm, this is set to Some, with the y + /// direction we're steering. + pub steer_dir: Option, /// If true, the owner has set this pet to stay at a fixed location and /// to not engage in combat pub is_pet_staying: bool, diff --git a/common/src/terrain/sprite.rs b/common/src/terrain/sprite.rs index 125a4c60ac..89e02d8950 100644 --- a/common/src/terrain/sprite.rs +++ b/common/src/terrain/sprite.rs @@ -566,22 +566,15 @@ impl SpriteKind { #[inline] pub fn mount_offset(&self) -> Option<(Vec3, Vec3)> { match self { - SpriteKind::ChairSingle | SpriteKind::ChairDouble | SpriteKind::Bench => Some(( - Vec3 { - x: 0.0, - y: 0.0, - z: 0.5, - }, - -Vec3::unit_y(), - )), - SpriteKind::Helm => Some(( - Vec3 { - x: 0.0, - y: -0.6, - z: 0.2, - }, - Vec3::unit_y(), - )), + SpriteKind::ChairSingle | SpriteKind::ChairDouble | SpriteKind::Bench => { + Some((Vec3::new(0.0, 0.0, 0.5), -Vec3::unit_y())) + }, + SpriteKind::Helm => Some((Vec3::new(0.0, -1.0, 0.0), Vec3::unit_y())), + SpriteKind::Bed => Some((Vec3::new(0.0, 0.0, 0.6), -Vec3::unit_y())), + SpriteKind::BedrollSnow | SpriteKind::BedrollPirate => { + Some((Vec3::new(0.0, 0.0, 0.1), -Vec3::unit_x())) + }, + SpriteKind::Bedroll => Some((Vec3::new(0.0, 0.0, 0.1), Vec3::unit_y())), _ => None, } } diff --git a/common/systems/src/mount.rs b/common/systems/src/mount.rs index ce6a7c46e4..c4a160efeb 100644 --- a/common/systems/src/mount.rs +++ b/common/systems/src/mount.rs @@ -1,5 +1,8 @@ use common::{ - comp::{Body, Collider, ControlAction, Controller, InputKind, Ori, Pos, Scale, Vel}, + comp::{ + Body, CharacterActivity, Collider, ControlAction, Controller, InputKind, Ori, Pos, Scale, + Vel, + }, link::Is, mounting::{Mount, VolumeRider}, terrain::TerrainGrid, @@ -24,6 +27,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Ori>, + WriteStorage<'a, CharacterActivity>, ReadStorage<'a, Body>, ReadStorage<'a, Scale>, ReadStorage<'a, Collider>, @@ -45,6 +49,7 @@ impl<'a> System<'a> for Sys { mut positions, mut velocities, mut orientations, + mut character_activity, bodies, scales, colliders, @@ -174,6 +179,9 @@ impl<'a> System<'a> for Sys { if is_volume_rider.block.is_controller() { if let Some((actions, inputs)) = inputs { + if let Some(mut character_activity) = character_activity.get_mut(entity) { + character_activity.steer_dir = Some(inputs.move_dir.y); + } match is_volume_rider.pos.kind { common::mounting::Volume::Entity(uid) => { if let Some(controller) = diff --git a/voxygen/anim/src/character/mod.rs b/voxygen/anim/src/character/mod.rs index 0c14bfc1a2..945d253008 100644 --- a/voxygen/anim/src/character/mod.rs +++ b/voxygen/anim/src/character/mod.rs @@ -28,11 +28,13 @@ pub mod selfbuff; pub mod shockwave; pub mod shoot; pub mod sit; +pub mod sleep; pub mod sneak; pub mod sneakequip; pub mod sneakwield; pub mod staggered; pub mod stand; +pub mod steer; pub mod stunned; pub mod swim; pub mod swimwield; @@ -51,11 +53,11 @@ pub use self::{ mount::MountAnimation, music::MusicAnimation, rapidmelee::RapidMeleeAnimation, repeater::RepeaterAnimation, ripostemelee::RiposteMeleeAnimation, roll::RollAnimation, run::RunAnimation, selfbuff::SelfBuffAnimation, shockwave::ShockwaveAnimation, - shoot::ShootAnimation, sit::SitAnimation, sneak::SneakAnimation, + shoot::ShootAnimation, sit::SitAnimation, sleep::SleepAnimation, sneak::SneakAnimation, sneakequip::SneakEquipAnimation, sneakwield::SneakWieldAnimation, - staggered::StaggeredAnimation, stand::StandAnimation, stunned::StunnedAnimation, - swim::SwimAnimation, swimwield::SwimWieldAnimation, talk::TalkAnimation, - wallrun::WallrunAnimation, wield::WieldAnimation, + staggered::StaggeredAnimation, stand::StandAnimation, steer::SteerAnimation, + stunned::StunnedAnimation, swim::SwimAnimation, swimwield::SwimWieldAnimation, + talk::TalkAnimation, wallrun::WallrunAnimation, wield::WieldAnimation, }; use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton, TrailSource}; use common::comp::{ diff --git a/voxygen/anim/src/character/sleep.rs b/voxygen/anim/src/character/sleep.rs new file mode 100644 index 0000000000..abeaa6ba96 --- /dev/null +++ b/voxygen/anim/src/character/sleep.rs @@ -0,0 +1,114 @@ +use super::{ + super::{vek::*, Animation}, + CharacterSkeleton, SkeletonAttr, +}; +use common::comp::item::ToolKind; +use std::{f32::consts::PI, ops::Mul}; + +pub struct SleepAnimation; + +impl Animation for SleepAnimation { + type Dependency<'a> = (Option, Option, f32); + type Skeleton = CharacterSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"character_sleep\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "character_sleep")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_active_tool_kind, _second_tool_kind, global_time): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let slow = (anim_time * 1.0).sin(); + let slowa = (anim_time * 1.0 + PI / 2.0).sin(); + let stop = (anim_time * 3.0).min(PI / 2.0).sin(); + + let head_look = Vec2::new( + (global_time * 0.05 + anim_time / 15.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + (global_time * 0.05 + anim_time / 15.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.1 + stop * -0.8); + next.head.orientation = Quaternion::rotation_z(head_look.x + slow * 0.2 - slow * 0.1) + * Quaternion::rotation_x((slowa * -0.1 + slow * 0.1 + head_look.y).abs()); + + next.chest.position = Vec3::new( + 0.0, + s_a.chest.0 + stop * -0.4, + s_a.chest.1 + slow * 0.1 + stop * -0.8, + ); + next.chest.orientation = Quaternion::rotation_x(stop * 0.15 + 1.0); + + next.belt.position = Vec3::new(0.0, s_a.belt.0 + stop * 1.2, s_a.belt.1); + next.belt.orientation = Quaternion::rotation_x(stop * 0.3); + + next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1); + + next.shorts.position = Vec3::new(0.0, s_a.shorts.0 + stop * 2.5, s_a.shorts.1 + stop * 0.6); + next.shorts.orientation = Quaternion::rotation_x(stop * 0.6); + + next.hand_l.position = Vec3::new( + -s_a.hand.0 - 1.0, + s_a.hand.1 + slowa * 0.15 + 2.0, + s_a.hand.2 + slow * 0.7 + stop * -2.0, + ); + next.hand_l.orientation = + Quaternion::rotation_x(slowa * -0.1 + slow * 0.1) * Quaternion::rotation_y(PI * 0.15); + + next.hand_r.position = Vec3::new( + s_a.hand.0 + 1.0, + s_a.hand.1 + slowa * 0.15 + 2.0, + s_a.hand.2 + slow * 0.7 + stop * -2.0, + ); + next.hand_r.orientation = + Quaternion::rotation_x(slow * -0.1 + slowa * 0.1) * Quaternion::rotation_y(PI * -0.15); + + next.foot_l.position = Vec3::new(-s_a.foot.0, 6.0 + s_a.foot.1, 6.0 + s_a.foot.2); + next.foot_l.orientation = Quaternion::rotation_x(slow * 0.1 + stop * 1.2 + slow * 0.1); + + next.foot_r.position = Vec3::new(s_a.foot.0, 6.0 + s_a.foot.1, 6.0 + s_a.foot.2); + next.foot_r.orientation = Quaternion::rotation_x(slowa * 0.1 + stop * 1.2 + slowa * 0.1); + + next.shoulder_l.position = Vec3::new(-s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + next.shoulder_l.orientation = Quaternion::rotation_x(0.0); + + next.shoulder_r.position = Vec3::new(s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + next.shoulder_r.orientation = Quaternion::rotation_x(0.0); + + next.torso.position = Vec3::new(0.0, -2.2, stop * -1.76); + + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 + 1.0 - head_look.x * 8.0, + s_a.hand.1 + 5.0 + head_look.x * 6.0, + s_a.hand.2 + 9.0 + head_look.y * 6.0, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 3.0) + * Quaternion::rotation_x(head_look.y * 3.0); + + let fast = (anim_time * 5.0).sin(); + let fast2 = (anim_time * 4.5 + 8.0).sin(); + + next.lantern.position = Vec3::new(-0.5, -0.5, -2.5); + next.lantern.orientation = next.hand_r.orientation.inverse() + * Quaternion::rotation_x(fast * 0.1) + * Quaternion::rotation_y(fast2 * 0.1); + } + + next + } +} diff --git a/voxygen/anim/src/character/steer.rs b/voxygen/anim/src/character/steer.rs new file mode 100644 index 0000000000..32bba0fe3e --- /dev/null +++ b/voxygen/anim/src/character/steer.rs @@ -0,0 +1,110 @@ +use super::{ + super::{vek::*, Animation}, + CharacterSkeleton, SkeletonAttr, +}; +use common::comp::item::ToolKind; +use std::{f32::consts::PI, ops::Mul}; + +pub struct SteerAnimation; + +impl Animation for SteerAnimation { + type Dependency<'a> = (Option, Option, f32, f32); + type Skeleton = CharacterSkeleton; + + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"character_steer\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "character_steer")] + fn update_skeleton_inner( + skeleton: &Self::Skeleton, + (_active_tool_kind, _second_tool_kind, steer_dir, global_time): Self::Dependency<'_>, + anim_time: f32, + _rate: &mut f32, + s_a: &SkeletonAttr, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let slow = (anim_time * 1.0).sin(); + let head_look = Vec2::new( + (global_time + anim_time / 12.0).floor().mul(7331.0).sin() * 0.1, + (global_time + anim_time / 12.0).floor().mul(1337.0).sin() * 0.05, + ); + next.head.scale = Vec3::one() * s_a.head_scale; + next.chest.scale = Vec3::one() * 1.01; + next.hand_l.scale = Vec3::one() * 1.04; + next.hand_r.scale = Vec3::one() * 1.04; + next.back.scale = Vec3::one() * 1.02; + next.hold.scale = Vec3::one() * 0.0; + next.lantern.scale = Vec3::one() * 0.65; + next.shoulder_l.scale = Vec3::one() * 1.1; + next.shoulder_r.scale = Vec3::one() * 1.1; + + next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1 + slow * 0.3); + next.head.orientation = + Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y.abs()); + + next.chest.position = Vec3::new(0.0, s_a.chest.0, s_a.chest.1 + slow * 0.3); + next.chest.orientation = Quaternion::rotation_z(head_look.x * 0.06); + + next.belt.position = Vec3::new(0.0, s_a.belt.0, s_a.belt.1); + next.belt.orientation = Quaternion::rotation_z(head_look.x * -0.1); + + next.back.position = Vec3::new(0.0, s_a.back.0, s_a.back.1); + + next.shorts.position = Vec3::new(0.0, s_a.shorts.0, s_a.shorts.1); + next.shorts.orientation = Quaternion::rotation_z(head_look.x * -0.2); + + next.hand_l.position = Vec3::new( + -s_a.hand.0, + s_a.hand.1 + slow * 0.15, + s_a.hand.2 + slow * 0.5, + ); + + let helm_center = Vec3::new(0.0, 0.6, 0.75) / s_a.scaler * 11.0; + + let rot = steer_dir * 0.5; + + let hand_rotation = Quaternion::rotation_y(rot) * Quaternion::rotation_x(PI / 2.0); + + let hand_offset = Vec3::new(rot.cos(), 0.0, -rot.sin()) * 0.4 / s_a.scaler * 11.0; + + next.hand_l.position = helm_center - hand_offset; + next.hand_l.orientation = hand_rotation; + + next.hand_r.position = helm_center + hand_offset; + next.hand_r.orientation = -hand_rotation; + + next.foot_l.position = Vec3::new(-s_a.foot.0, s_a.foot.1, s_a.foot.2); + next.foot_l.orientation = Quaternion::identity(); + + next.foot_r.position = Vec3::new(s_a.foot.0, s_a.foot.1, s_a.foot.2); + next.foot_r.orientation = Quaternion::identity(); + + next.shoulder_l.position = Vec3::new(-s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + + next.shoulder_r.position = Vec3::new(s_a.shoulder.0, s_a.shoulder.1, s_a.shoulder.2); + + next.glider.position = Vec3::new(0.0, 0.0, 10.0); + next.glider.scale = Vec3::one() * 0.0; + next.hold.position = Vec3::new(0.4, -0.3, -5.8); + + if skeleton.holding_lantern { + next.hand_r.position = Vec3::new( + s_a.hand.0 - head_look.x * 6.0, + s_a.hand.1 + 5.0 - head_look.y * 10.0 + slow * 0.15, + s_a.hand.2 + 12.0 + head_look.y * 6.0 + slow * 0.5, + ); + next.hand_r.orientation = Quaternion::rotation_x(2.25 + slow * -0.06) + * Quaternion::rotation_z(0.9) + * Quaternion::rotation_y(head_look.x * 1.5) + * Quaternion::rotation_x(head_look.y * 1.5); + + next.lantern.position = Vec3::new(-0.5, -0.5, -2.5); + next.lantern.orientation = next.hand_r.orientation.inverse(); + } + + next.torso.position = Vec3::new(0.0, 0.0, 0.0); + + next + } +} diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index d9f6a37e17..ebe20dbb65 100755 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -2155,6 +2155,7 @@ impl Hud { BlockInteraction::Mount => { let key = match block.get_sprite() { Some(SpriteKind::Helm) => "hud-steer", + Some(SpriteKind::Bed | SpriteKind::Bedroll | SpriteKind::BedrollSnow | SpriteKind::BedrollPirate) => "hud-lay", _ => "hud-sit", }; vec![(Some(GameInput::Mount), i18n.get_msg(key).to_string())] diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 84f2d9d753..4ac0c3afb8 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -1110,7 +1110,10 @@ impl FigureMgr { && matches!(active_tool_hand, Some(Hands::One))) || !character.map_or(false, |c| c.is_wield())) && !character.map_or(false, |c| c.is_using_hands()) - && physics.in_liquid().is_none(); + && physics.in_liquid().is_none() + && is_volume_rider.map_or(true, |volume_rider| { + !matches!(volume_rider.block.get_sprite(), Some(SpriteKind::Helm)) + }); let back_carry_offset = inventory .and_then(|i| i.equipped(EquipSlot::Armor(ArmorSlot::Back))) @@ -2137,7 +2140,26 @@ impl FigureMgr { { match sprite { SpriteKind::Helm => { - anim::character::DanceAnimation::update_skeleton( + anim::character::SteerAnimation::update_skeleton( + &target_base, + ( + active_tool_kind, + second_tool_kind, + character_activity + .and_then(|a| a.steer_dir) + .unwrap_or(0.0), + time, + ), + state.state_time, + &mut state_animation_rate, + skeleton_attr, + ) + }, + SpriteKind::Bed + | SpriteKind::Bedroll + | SpriteKind::BedrollSnow + | SpriteKind::BedrollPirate => { + anim::character::SleepAnimation::update_skeleton( &target_base, (active_tool_kind, second_tool_kind, time), state.state_time,