Split animations

This commit is contained in:
timokoesters 2019-08-26 00:22:43 +02:00 committed by jshipsey
parent e674424974
commit 637b4642d8
2 changed files with 182 additions and 151 deletions

View File

@ -282,7 +282,26 @@ impl Client {
// Handle new messages from the server. // Handle new messages from the server.
frontend_events.append(&mut self.handle_new_messages()?); frontend_events.append(&mut self.handle_new_messages()?);
// 3) // 3) Update client local data
{
let ecs = self.state.ecs_mut();
for (entity, _) in (&ecs.entities(), &ecs.read_storage::<comp::Body>()).join() {
let mut last_character_state =
ecs.write_storage::<comp::Last<comp::CharacterState>>();
if let Some(client_character_state) =
ecs.read_storage::<comp::CharacterState>().get(entity)
{
if last_character_state
.get(entity)
.map(|&l| l != *client_character_state)
.unwrap_or(true)
{
let _ = last_character_state
.insert(entity, comp::Last(*client_character_state));
}
}
}
}
// 4) Tick the client's LocalState // 4) Tick the client's LocalState
self.state.tick(dt); self.state.tick(dt);
@ -395,7 +414,6 @@ impl Client {
} }
// 7) Finish the tick, pass control back to the frontend. // 7) Finish the tick, pass control back to the frontend.
self.tick += 1; self.tick += 1;
Ok(frontend_events) Ok(frontend_events)
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
anim::{ anim::{
self, character::CharacterSkeleton, object::ObjectSkeleton, quadruped::QuadrupedSkeleton, self, character::CharacterSkeleton, object::ObjectSkeleton, quadruped::QuadrupedSkeleton,
quadrupedmedium::QuadrupedMediumSkeleton, Animation, Skeleton, SkeletonAttr, quadrupedmedium::QuadrupedMediumSkeleton, Animation as _, Skeleton, SkeletonAttr,
}, },
mesh::Meshable, mesh::Meshable,
render::{ render::{
@ -13,7 +13,9 @@ use client::Client;
use common::{ use common::{
assets, assets,
comp::{ comp::{
self, humanoid, item::Tool, object, quadruped, quadruped_medium, Body, Equipment, Item,
self, humanoid, item::Tool, object, quadruped, quadruped_medium, Body, Equipment, Item, ActionState::*, Animation, Body,
CharacterState, Last, MovementState::*, Ori, Pos, Scale, Stats, Vel,
}, },
figure::Segment, figure::Segment,
terrain::TerrainChunkSize, terrain::TerrainChunkSize,
@ -23,7 +25,7 @@ use dot_vox::DotVoxData;
use hashbrown::HashMap; use hashbrown::HashMap;
use log::debug; use log::debug;
use specs::{Entity as EcsEntity, Join}; use specs::{Entity as EcsEntity, Join};
use std::f32; use std::{f32, time::Instant};
use vek::*; use vek::*;
const DAMAGE_FADE_COEFFICIENT: f64 = 5.0; const DAMAGE_FADE_COEFFICIENT: f64 = 5.0;
@ -618,19 +620,20 @@ impl FigureMgr {
let dt = client.state().get_delta_time(); let dt = client.state().get_delta_time();
// Get player position. // Get player position.
let player_pos = ecs let player_pos = ecs
.read_storage::<comp::Pos>() .read_storage::<Pos>()
.get(client.entity()) .get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0); .map_or(Vec3::zero(), |pos| pos.0);
for (entity, pos, vel, ori, scale, body, animation_info, stats) in ( for (entity, pos, vel, ori, scale, body, character, last_character, stats) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<comp::Pos>(), &ecs.read_storage::<Pos>(),
&ecs.read_storage::<comp::Vel>(), &ecs.read_storage::<Vel>(),
&ecs.read_storage::<comp::Ori>(), &ecs.read_storage::<Ori>(),
ecs.read_storage::<comp::Scale>().maybe(), ecs.read_storage::<Scale>().maybe(),
&ecs.read_storage::<comp::Body>(), &ecs.read_storage::<Body>(),
ecs.read_storage::<comp::AnimationInfo>().maybe(), ecs.read_storage::<CharacterState>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(), ecs.read_storage::<Last<CharacterState>>().maybe(),
ecs.read_storage::<Stats>().maybe(),
) )
.join() .join()
{ {
@ -683,80 +686,84 @@ impl FigureMgr {
.character_states .character_states
.entry(entity) .entry(entity)
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
let (character, last_character) = match (character, last_character) {
let animation_info = match animation_info { (Some(c), Some(l)) => (c, l),
Some(a_i) => a_i, _ => continue,
None => continue,
}; };
let target_skeleton = match animation_info.animation { if last_character.0.movement != character.movement {
comp::Animation::Idle => anim::character::IdleAnimation::update_skeleton( state.last_movement_change = Instant::now();
state.skeleton_mut(), }
time, if last_character.0.action != character.action {
animation_info.time, state.last_action_change = Instant::now();
skeleton_attr, }
),
comp::Animation::Run => anim::character::RunAnimation::update_skeleton( let time_since_movement_change =
state.skeleton_mut(), state.last_movement_change.elapsed().as_secs_f64();
(vel.0.magnitude(), time), let time_since_action_change = state.last_action_change.elapsed().as_secs_f64();
animation_info.time,
skeleton_attr, let target_movement = match &character.movement {
), Stand => anim::character::IdleAnimation::update_skeleton(
comp::Animation::Jump => anim::character::JumpAnimation::update_skeleton( state.skeleton_mut(),
state.skeleton_mut(), time,
time, time_since_movement_change,
animation_info.time, skeleton_attr,
skeleton_attr, ),
), Run => anim::character::RunAnimation::update_skeleton(
comp::Animation::Attack => { state.skeleton_mut(),
anim::character::AttackAnimation::update_skeleton( (vel.0.magnitude(), time),
state.skeleton_mut(), time_since_movement_change,
time, skeleton_attr,
animation_info.time, ),
skeleton_attr, Jump => anim::character::JumpAnimation::update_skeleton(
) state.skeleton_mut(),
} time,
comp::Animation::Block => anim::character::BlockAnimation::update_skeleton( time_since_movement_change,
state.skeleton_mut(), skeleton_attr,
time, ),
animation_info.time, Roll { .. } => anim::character::RollAnimation::update_skeleton(
skeleton_attr, state.skeleton_mut(),
), time,
comp::Animation::Cjump => anim::character::CjumpAnimation::update_skeleton( time_since_movement_change,
state.skeleton_mut(), skeleton_attr,
time, ),
animation_info.time, Glide => anim::character::GlidingAnimation::update_skeleton(
skeleton_attr, state.skeleton_mut(),
), (vel.0.magnitude(), time),
comp::Animation::Roll => anim::character::RollAnimation::update_skeleton( time_since_movement_change,
state.skeleton_mut(), skeleton_attr,
time, ),
animation_info.time, };
skeleton_attr, state.skeleton.interpolate(&target_movement, dt);
),
comp::Animation::Crun => anim::character::CrunAnimation::update_skeleton( let target_action = match &character.action {
state.skeleton_mut(), Idle => anim::character::IdleAnimation::update_skeleton(
(vel.0.magnitude(), time), state.skeleton_mut(),
animation_info.time, time,
skeleton_attr, time_since_action_change,
), skeleton_attr,
comp::Animation::Cidle => anim::character::CidleAnimation::update_skeleton( ),
state.skeleton_mut(), Wield { .. } => anim::character::CidleAnimation::update_skeleton(
time, state.skeleton_mut(),
animation_info.time, time,
skeleton_attr, time_since_action_change,
), skeleton_attr,
comp::Animation::Gliding => { ),
anim::character::GlidingAnimation::update_skeleton( Attack { .. } => anim::character::AttackAnimation::update_skeleton(
state.skeleton_mut(), state.skeleton_mut(),
(vel.0.magnitude(), time), time,
animation_info.time, time_since_action_change,
skeleton_attr, skeleton_attr,
) ),
} Block { .. } => anim::character::BlockAnimation::update_skeleton(
}; state.skeleton_mut(),
time,
time_since_action_change,
skeleton_attr,
),
};
state.skeleton.interpolate(&target_action, dt);
state.skeleton.interpolate(&target_skeleton, dt);
state.update(renderer, pos.0, ori.0, scale, col, dt); state.update(renderer, pos.0, ori.0, scale, col, dt);
} }
Body::Quadruped(_) => { Body::Quadruped(_) => {
@ -765,42 +772,43 @@ impl FigureMgr {
.entry(entity) .entry(entity)
.or_insert_with(|| FigureState::new(renderer, QuadrupedSkeleton::new())); .or_insert_with(|| FigureState::new(renderer, QuadrupedSkeleton::new()));
let animation_info = match animation_info { let (character, last_character) = match (character, last_character) {
Some(a_i) => a_i, (Some(c), Some(l)) => (c, l),
None => continue, _ => continue,
}; };
let target_skeleton = match animation_info.animation { if last_character.0.movement != character.movement {
comp::Animation::Run | comp::Animation::Crun => { state.last_movement_change = Instant::now();
anim::quadruped::RunAnimation::update_skeleton( }
state.skeleton_mut(),
(vel.0.magnitude(), time), let time_since_movement_change =
animation_info.time, state.last_movement_change.elapsed().as_secs_f64();
skeleton_attr,
) let target_movement = match character.movement {
} Stand => anim::quadruped::IdleAnimation::update_skeleton(
comp::Animation::Idle | comp::Animation::Cidle => { state.skeleton_mut(),
anim::quadruped::IdleAnimation::update_skeleton( time,
state.skeleton_mut(), time_since_movement_change,
time, skeleton_attr,
animation_info.time, ),
skeleton_attr, Run => anim::quadruped::RunAnimation::update_skeleton(
) state.skeleton_mut(),
} (vel.0.magnitude(), time),
comp::Animation::Jump | comp::Animation::Cjump => { time_since_movement_change,
anim::quadruped::JumpAnimation::update_skeleton( skeleton_attr,
state.skeleton_mut(), ),
(vel.0.magnitude(), time), Jump => anim::quadruped::JumpAnimation::update_skeleton(
animation_info.time, state.skeleton_mut(),
skeleton_attr, (vel.0.magnitude(), time),
) time_since_movement_change,
} skeleton_attr,
),
// TODO! // TODO!
_ => state.skeleton_mut().clone(), _ => state.skeleton_mut().clone(),
}; };
state.skeleton.interpolate(&target_skeleton, dt); state.skeleton.interpolate(&target_movement, dt);
state.update(renderer, pos.0, ori.0, scale, col, dt); state.update(renderer, pos.0, ori.0, scale, col, dt);
} }
Body::QuadrupedMedium(_) => { Body::QuadrupedMedium(_) => {
@ -811,42 +819,43 @@ impl FigureMgr {
FigureState::new(renderer, QuadrupedMediumSkeleton::new()) FigureState::new(renderer, QuadrupedMediumSkeleton::new())
}); });
let animation_info = match animation_info { let (character, last_character) = match (character, last_character) {
Some(a_i) => a_i, (Some(c), Some(l)) => (c, l),
None => continue, _ => continue,
}; };
let target_skeleton = match animation_info.animation { if last_character.0.movement != character.movement {
comp::Animation::Run | comp::Animation::Crun => { state.last_movement_change = Instant::now();
anim::quadrupedmedium::RunAnimation::update_skeleton( }
state.skeleton_mut(),
(vel.0.magnitude(), time), let time_since_movement_change =
animation_info.time, state.last_movement_change.elapsed().as_secs_f64();
skeleton_attr,
) let target_movement = match character.movement {
} Stand => anim::quadrupedmedium::IdleAnimation::update_skeleton(
comp::Animation::Idle | comp::Animation::Cidle => { state.skeleton_mut(),
anim::quadrupedmedium::IdleAnimation::update_skeleton( time,
state.skeleton_mut(), time_since_movement_change,
time, skeleton_attr,
animation_info.time, ),
skeleton_attr, Run => anim::quadrupedmedium::RunAnimation::update_skeleton(
) state.skeleton_mut(),
} (vel.0.magnitude(), time),
comp::Animation::Jump | comp::Animation::Cjump => { time_since_movement_change,
anim::quadrupedmedium::JumpAnimation::update_skeleton( skeleton_attr,
state.skeleton_mut(), ),
(vel.0.magnitude(), time), Jump => anim::quadrupedmedium::JumpAnimation::update_skeleton(
animation_info.time, state.skeleton_mut(),
skeleton_attr, (vel.0.magnitude(), time),
) time_since_movement_change,
} skeleton_attr,
),
// TODO! // TODO!
_ => state.skeleton_mut().clone(), _ => state.skeleton_mut().clone(),
}; };
state.skeleton.interpolate(&target_skeleton, dt); state.skeleton.interpolate(&target_movement, dt);
state.update(renderer, pos.0, ori.0, scale, col, dt); state.update(renderer, pos.0, ori.0, scale, col, dt);
} }
Body::Object(_) => { Body::Object(_) => {
@ -887,12 +896,12 @@ impl FigureMgr {
for (entity, _, _, _, body, stats, _) in ( for (entity, _, _, _, body, stats, _) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<comp::Pos>(), &ecs.read_storage::<Pos>(),
&ecs.read_storage::<comp::Vel>(), &ecs.read_storage::<Vel>(),
&ecs.read_storage::<comp::Ori>(), &ecs.read_storage::<Ori>(),
&ecs.read_storage::<comp::Body>(), &ecs.read_storage::<Body>(),
ecs.read_storage::<comp::Stats>().maybe(), ecs.read_storage::<Stats>().maybe(),
ecs.read_storage::<comp::Scale>().maybe(), ecs.read_storage::<Scale>().maybe(),
) )
.join() .join()
// Don't render figures outside of frustum (camera viewport, max draw distance is farplane) // Don't render figures outside of frustum (camera viewport, max draw distance is farplane)
@ -901,7 +910,7 @@ impl FigureMgr {
&pos.0.x, &pos.0.x,
&pos.0.y, &pos.0.y,
&pos.0.z, &pos.0.z,
&(scale.unwrap_or(&comp::Scale(1.0)).0 * 2.0), &(scale.unwrap_or(&Scale(1.0)).0 * 2.0),
) )
}) })
// Don't render dead entities // Don't render dead entities
@ -934,7 +943,7 @@ impl FigureMgr {
if camera.get_mode() == CameraMode::FirstPerson if camera.get_mode() == CameraMode::FirstPerson
&& client && client
.state() .state()
.read_storage::<comp::Body>() .read_storage::<Body>()
.get(client.entity()) .get(client.entity())
.is_some() .is_some()
&& entity == client.entity() && entity == client.entity()
@ -953,6 +962,8 @@ impl FigureMgr {
pub struct FigureState<S: Skeleton> { pub struct FigureState<S: Skeleton> {
bone_consts: Consts<FigureBoneData>, bone_consts: Consts<FigureBoneData>,
locals: Consts<FigureLocals>, locals: Consts<FigureLocals>,
last_movement_change: Instant,
last_action_change: Instant,
skeleton: S, skeleton: S,
pos: Vec3<f32>, pos: Vec3<f32>,
ori: Vec3<f32>, ori: Vec3<f32>,
@ -965,6 +976,8 @@ impl<S: Skeleton> FigureState<S> {
.create_consts(&skeleton.compute_matrices()) .create_consts(&skeleton.compute_matrices())
.unwrap(), .unwrap(),
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(), locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
last_movement_change: Instant::now(),
last_action_change: Instant::now(),
skeleton, skeleton,
pos: Vec3::zero(), pos: Vec3::zero(),
ori: Vec3::zero(), ori: Vec3::zero(),