diff --git a/common/src/comp/actor.rs b/common/src/comp/actor.rs index 109c90ceb8..f17a9f9262 100644 --- a/common/src/comp/actor.rs +++ b/common/src/comp/actor.rs @@ -253,6 +253,7 @@ pub enum Animation { Run, Jump, Gliding, + Attack, } impl Component for AnimationHistory { diff --git a/common/src/sys/control.rs b/common/src/sys/control.rs index 0fa60fe0d0..df1b63fc26 100644 --- a/common/src/sys/control.rs +++ b/common/src/sys/control.rs @@ -86,7 +86,7 @@ impl<'a> System<'a> for Sys { if control.move_dir.magnitude() > 0.01 { Animation::Run } else { - Animation::Idle + Animation::Attack } } else if gliding { Animation::Gliding diff --git a/voxygen/src/anim/character/attack.rs b/voxygen/src/anim/character/attack.rs new file mode 100644 index 0000000000..000ef57c92 --- /dev/null +++ b/voxygen/src/anim/character/attack.rs @@ -0,0 +1,116 @@ +// Standard +use std::{f32::consts::PI, ops::Mul}; + +// Library +use vek::*; + +// Local +use super::{super::Animation, CharacterSkeleton, SCALE}; + +pub struct Input { + pub attack: bool, +} +pub struct AttackAnimation; + +impl Animation for AttackAnimation { + type Skeleton = CharacterSkeleton; + type Dependency = f64; + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: f64, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 1.0).sin(); + let wave_cos = (anim_time as f32 * 12.0).cos(); + let wave_slow = (anim_time as f32 * 6.0 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 6.0 + PI).cos(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_dip = (wave_slow.abs() - 0.5).abs(); + + let head_look = Vec2::new( + ((global_time + anim_time) as f32 / 8.0) + .floor() + .mul(7331.0) + .sin() + * 0.5, + ((global_time + anim_time) as f32 / 8.0) + .floor() + .mul(1337.0) + .sin() + * 0.25, + ); + next.head.offset = Vec3::new(5.5, 2.0, 11.0 + wave_ultra_slow * 0.3); + next.head.ori = Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y); + next.head.scale = Vec3::one(); + + next.chest.offset = Vec3::new(5.5, 0.0, 7.0 + wave_ultra_slow * 0.3); + next.chest.ori = Quaternion::rotation_x(0.0); + next.chest.scale = Vec3::one(); + + next.belt.offset = Vec3::new(5.5, 0.0, 5.0 + wave_ultra_slow * 0.3); + next.belt.ori = Quaternion::rotation_x(0.0); + next.belt.scale = Vec3::one(); + + next.shorts.offset = Vec3::new(5.5, 0.0, 2.0 + wave_ultra_slow * 0.3); + next.shorts.ori = Quaternion::rotation_x(0.0); + next.shorts.scale = Vec3::one(); + + next.l_hand.offset = Vec3::new( + -6.0, + -2.0 + wave_ultra_slow_cos * 0.15, + 11.5 + wave_ultra_slow * 0.5, + ); + + next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06); + next.l_hand.scale = Vec3::one(); + + next.r_hand.offset = Vec3::new( + 9.0, + -2.0 + wave_ultra_slow_cos * 0.15, + 11.5 + wave_ultra_slow * 0.5, + ); + next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * 0.06); + next.r_hand.scale = Vec3::one(); + + next.l_foot.offset = Vec3::new(-3.3, -0.1, 8.0); + next.l_foot.ori = Quaternion::identity(); + next.l_foot.scale = Vec3::one(); + + next.r_foot.offset = Vec3::new(4.1, -0.1, 8.0); + next.r_foot.ori = Quaternion::identity(); + next.r_foot.scale = Vec3::one(); + + next.weapon.offset = Vec3::new(-5.0, -6.0, 18.0); + next.weapon.ori = Quaternion::rotation_z(wave * 1.0); + next.weapon.scale = Vec3::one(); + + next.l_shoulder.offset = Vec3::new(-10.0, -3.0, 2.5); + next.l_shoulder.ori = Quaternion::rotation_x(0.0); + next.l_shoulder.scale = Vec3::one(); + + next.r_shoulder.offset = Vec3::new(0.0, -3.0, 2.5); + next.r_shoulder.ori = Quaternion::rotation_x(0.0); + next.r_shoulder.scale = Vec3::one(); + + next.draw.offset = Vec3::new(13.5, 0.0, 0.0); + next.draw.ori = Quaternion::rotation_y(0.0); + next.draw.scale = Vec3::one() * 0.0; + + next.l_hold.offset = Vec3::new(0.0, 0.0, 5.0); + next.l_hold.ori = Quaternion::rotation_x(0.0); + next.l_hold.scale = Vec3::one(); + + next.r_hold.offset = Vec3::new(-2.0, -2.5, 0.0); + next.r_hold.ori = Quaternion::rotation_x(0.0); + next.r_hold.scale = Vec3::one(); + + next.torso.offset = Vec3::new(-0.5, -0.2, 0.1); + next.torso.ori = Quaternion::rotation_x(0.0); + next.torso.scale = Vec3::one() / 11.0; + next + } +} diff --git a/voxygen/src/anim/character/gliding.rs b/voxygen/src/anim/character/gliding.rs index 1374ed9497..2bdb528f66 100644 --- a/voxygen/src/anim/character/gliding.rs +++ b/voxygen/src/anim/character/gliding.rs @@ -102,15 +102,23 @@ impl Animation for GlidingAnimation { next.r_shoulder.offset = Vec3::new(0.0, -3.0, 2.5); next.r_shoulder.ori = Quaternion::rotation_x(0.0); next.r_shoulder.scale = Vec3::one(); + + next.draw.offset = Vec3::new(13.5, 3.0, -1.0); + next.draw.ori = Quaternion::rotation_y(wave_very_slow_cos * 0.05); + next.draw.scale = Vec3::one(); + + next.l_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.l_hold.ori = Quaternion::rotation_x(0.0); + next.l_hold.scale = Vec3::one(); + + next.r_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.r_hold.ori = Quaternion::rotation_x(0.0); + next.r_hold.scale = Vec3::one(); next.torso.offset = Vec3::new(-0.5, -0.2, 0.0); next.torso.ori = Quaternion::rotation_x(-0.8 + wave_very_slow * 0.10); next.torso.scale = Vec3::one() / 11.0; - next.draw.offset = Vec3::new(13.5, 3.0, -1.0); - next.draw.ori = Quaternion::rotation_y(wave_very_slow_cos * 0.05); - next.draw.scale = Vec3::one(); - next } } diff --git a/voxygen/src/anim/character/idle.rs b/voxygen/src/anim/character/idle.rs index 79f7ce8b2d..d7cc70153f 100644 --- a/voxygen/src/anim/character/idle.rs +++ b/voxygen/src/anim/character/idle.rs @@ -96,13 +96,23 @@ impl Animation for IdleAnimation { next.r_shoulder.ori = Quaternion::rotation_x(0.0); next.r_shoulder.scale = Vec3::one(); + next.draw.offset = Vec3::new(13.5, 0.0, 0.0); + next.draw.ori = Quaternion::rotation_y(0.0); + next.draw.scale = Vec3::one() * 0.0; + + next.l_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.l_hold.ori = Quaternion::rotation_x(0.0); + next.l_hold.scale = Vec3::one(); + + next.r_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.r_hold.ori = Quaternion::rotation_x(0.0); + next.r_hold.scale = Vec3::one(); + next.torso.offset = Vec3::new(-0.5, -0.2, 0.1); next.torso.ori = Quaternion::rotation_x(0.0); next.torso.scale = Vec3::one() / 11.0; - next.draw.offset = Vec3::new(13.5, 0.0, 0.0); - next.draw.ori = Quaternion::rotation_y(0.0); - next.draw.scale = Vec3::one() * 0.0; + next } } diff --git a/voxygen/src/anim/character/jump.rs b/voxygen/src/anim/character/jump.rs index d72cad95d3..d9b63cd65e 100644 --- a/voxygen/src/anim/character/jump.rs +++ b/voxygen/src/anim/character/jump.rs @@ -75,13 +75,24 @@ impl Animation for JumpAnimation { next.r_shoulder.ori = Quaternion::rotation_x(0.0); next.r_shoulder.scale = Vec3::one(); + next.draw.offset = Vec3::new(13.5, 0.0, 0.0); + next.draw.ori = Quaternion::rotation_y(0.0); + next.draw.scale = Vec3::one() * 0.0; + + next.l_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.l_hold.ori = Quaternion::rotation_x(0.0); + next.l_hold.scale = Vec3::one(); + + next.r_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.r_hold.ori = Quaternion::rotation_x(0.0); + next.r_hold.scale = Vec3::one(); + next.torso.offset = Vec3::new(-0.5, -0.2, 0.0); next.torso.ori = Quaternion::rotation_x(-0.2); next.torso.scale = Vec3::one() / 11.0; - next.draw.offset = Vec3::new(13.5, 0.0, 0.0); - next.draw.ori = Quaternion::rotation_y(0.0); - next.draw.scale = Vec3::one() * 0.0; + + next } } diff --git a/voxygen/src/anim/character/mod.rs b/voxygen/src/anim/character/mod.rs index d1054716a5..9935aa496d 100644 --- a/voxygen/src/anim/character/mod.rs +++ b/voxygen/src/anim/character/mod.rs @@ -2,12 +2,15 @@ pub mod gliding; pub mod idle; pub mod jump; pub mod run; +pub mod attack; // Reexports pub use self::gliding::GlidingAnimation; pub use self::idle::IdleAnimation; pub use self::jump::JumpAnimation; pub use self::run::RunAnimation; +pub use self::attack::AttackAnimation; + // Crate use crate::render::FigureBoneData; @@ -30,6 +33,8 @@ pub struct CharacterSkeleton { l_shoulder: Bone, r_shoulder: Bone, draw: Bone, + l_hold: Bone, + r_hold: Bone, torso: Bone, } @@ -48,6 +53,8 @@ impl CharacterSkeleton { l_shoulder: Bone::default(), r_shoulder: Bone::default(), draw: Bone::default(), + l_hold: Bone::default(), + r_hold: Bone::default(), torso: Bone::default(), } } @@ -58,6 +65,7 @@ impl Skeleton for CharacterSkeleton { let chest_mat = self.chest.compute_base_matrix(); let torso_mat = self.torso.compute_base_matrix(); let l_hand_mat = self.l_hand.compute_base_matrix(); + let weapon_mat = self.weapon.compute_base_matrix(); [ FigureBoneData::new(torso_mat * self.head.compute_base_matrix()), FigureBoneData::new(torso_mat * chest_mat), @@ -67,14 +75,14 @@ impl Skeleton for CharacterSkeleton { FigureBoneData::new(torso_mat * self.r_hand.compute_base_matrix()), FigureBoneData::new(torso_mat * self.l_foot.compute_base_matrix()), FigureBoneData::new(torso_mat * self.r_foot.compute_base_matrix()), - FigureBoneData::new(torso_mat * chest_mat * self.weapon.compute_base_matrix()), + FigureBoneData::new(torso_mat * chest_mat * weapon_mat), FigureBoneData::new(torso_mat * chest_mat * self.l_shoulder.compute_base_matrix()), FigureBoneData::new(torso_mat * chest_mat * self.r_shoulder.compute_base_matrix()), FigureBoneData::new(torso_mat * l_hand_mat * self.draw.compute_base_matrix()), + FigureBoneData::new(torso_mat * weapon_mat * self.l_hold.compute_base_matrix()), + FigureBoneData::new(torso_mat * weapon_mat * self.r_hold.compute_base_matrix()), FigureBoneData::new(torso_mat), FigureBoneData::default(), - FigureBoneData::default(), - FigureBoneData::default(), ] } @@ -91,6 +99,8 @@ impl Skeleton for CharacterSkeleton { self.l_shoulder.interpolate(&target.l_shoulder); self.r_shoulder.interpolate(&target.r_shoulder); self.draw.interpolate(&target.draw); + self.l_hold.interpolate(&target.l_hold); + self.r_hold.interpolate(&target.r_hold); self.torso.interpolate(&target.torso); } } diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index fa72a5e70a..c92aea58db 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -80,6 +80,14 @@ impl Animation for RunAnimation { next.draw.ori = Quaternion::rotation_y(0.0); next.draw.scale = Vec3::one() * 0.0; + next.l_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.l_hold.ori = Quaternion::rotation_x(0.0); + next.l_hold.scale = Vec3::one(); + + next.r_hold.offset = Vec3::new(0.0, 0.0, 0.0); + next.r_hold.ori = Quaternion::rotation_x(0.0); + next.r_hold.scale = Vec3::one(); + next } } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 301f4d5a4c..2c12797791 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -69,8 +69,8 @@ impl FigureModelCache { Some(Self::load_left_shoulder(body.shoulder)), Some(Self::load_right_shoulder(body.shoulder)), Some(Self::load_draw(body.draw)), - None, - None, + Some(Self::load_left_hold(body.hand)), + Some(Self::load_right_hold(body.hand)), None, None, ], @@ -221,7 +221,7 @@ impl FigureModelCache { // TODO actually match against other weapons and set the right model _ => "weapon/sword/sword_wood_2h.vox", }, - Vec3::new(0.0, 0.0, -4.0), + Vec3::new(-6.5, -1.5, -4.0), ) } @@ -242,6 +242,7 @@ impl FigureModelCache { Vec3::new(2.5, -0.5, 0.0), ) } + fn load_draw(draw: Draw) -> Mesh { Self::load_mesh( match draw { @@ -251,6 +252,24 @@ impl FigureModelCache { ) } + fn load_left_hold(hand: Hand) -> Mesh { + Self::load_mesh( + match hand { + Hand::Default => "figure/body/hand.vox", + }, + Vec3::new(0.0, -2.5, 0.0), + ) + } + + fn load_right_hold(hand: Hand) -> Mesh { + Self::load_mesh( + match hand { + Hand::Default => "figure/body/hand.vox", + }, + Vec3::new(-2.0, -2.5, 0.0), + ) + } + fn load_pig_head(pig_head: PigHead) -> Mesh { Self::load_mesh( match pig_head { @@ -362,6 +381,11 @@ impl FigureMgr { time, animation_history.time, ), + comp::Animation::Attack => character::AttackAnimation::update_skeleton( + state.skeleton_mut(), + time, + animation_history.time, + ), comp::Animation::Gliding => { character::GlidingAnimation::update_skeleton( state.skeleton_mut(),