From 1dc654dde79e262fa85650c7a546453ecd270b18 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 21 Jul 2019 13:42:45 +0100 Subject: [PATCH] Added object entities --- client/src/lib.rs | 4 +- common/src/comp/body.rs | 2 + common/src/comp/body/object.rs | 18 +++++ common/src/comp/mod.rs | 2 +- common/src/msg/server.rs | 2 +- common/src/sys/action_state.rs | 2 +- common/src/sys/mod.rs | 3 + common/src/sys/movement.rs | 138 ++++++++++++++++++++++++++++++++ common/src/sys/phys.rs | 91 +-------------------- server/src/cmd.rs | 29 ++++++- server/src/lib.rs | 30 +++++-- voxygen/src/anim/fixture/mod.rs | 1 + voxygen/src/anim/mod.rs | 1 + voxygen/src/anim/object/mod.rs | 39 +++++++++ voxygen/src/scene/figure.rs | 78 ++++++++++++++++-- voxygen/src/scene/mod.rs | 5 +- 16 files changed, 335 insertions(+), 110 deletions(-) create mode 100644 common/src/comp/body/object.rs create mode 100644 common/src/sys/movement.rs create mode 100644 voxygen/src/anim/object/mod.rs diff --git a/client/src/lib.rs b/client/src/lib.rs index a75a4a34fe..a4985eebd5 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -403,7 +403,9 @@ impl Client { self.state.write_component(entity, pos); self.state.write_component(entity, vel); self.state.write_component(entity, ori); - self.state.write_component(entity, action_state); + if let Some(a_s) = action_state { + self.state.write_component(entity, a_s); + } } } ServerMsg::TerrainChunkUpdate { key, chunk } => { diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 0febc1e799..4c9ae82124 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -1,4 +1,5 @@ pub mod humanoid; +pub mod object; pub mod quadruped; pub mod quadruped_medium; @@ -9,6 +10,7 @@ pub enum Body { Humanoid(humanoid::Body), Quadruped(quadruped::Body), QuadrupedMedium(quadruped_medium::Body), + Object(object::Body), } impl Component for Body { diff --git a/common/src/comp/body/object.rs b/common/src/comp/body/object.rs new file mode 100644 index 0000000000..54133c9f0a --- /dev/null +++ b/common/src/comp/body/object.rs @@ -0,0 +1,18 @@ +use rand::{seq::SliceRandom, thread_rng}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Body { + Bomb, + Scarecrow, + Chest, + Pumpkin, +} + +impl Body { + pub fn random() -> Self { + let mut rng = thread_rng(); + *(&ALL_OBJECTS).choose(&mut rng).unwrap() + } +} + +const ALL_OBJECTS: [Body; 4] = [Body::Bomb, Body::Scarecrow, Body::Chest, Body::Pumpkin]; diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index d7d5c211dd..655177b0ee 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -13,7 +13,7 @@ mod stats; pub use action_state::ActionState; pub use agent::Agent; pub use animation::{Animation, AnimationInfo}; -pub use body::{humanoid, quadruped, quadruped_medium, Body}; +pub use body::{humanoid, object, quadruped, quadruped_medium, Body}; pub use controller::Controller; pub use inputs::{ Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding, diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 06c53af40f..636a33326a 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -40,7 +40,7 @@ pub enum ServerMsg { pos: comp::Pos, vel: comp::Vel, ori: comp::Ori, - action_state: comp::ActionState, + action_state: Option, }, TerrainChunkUpdate { key: Vec2, diff --git a/common/src/sys/action_state.rs b/common/src/sys/action_state.rs index d5852bf648..fd8d1ee11a 100644 --- a/common/src/sys/action_state.rs +++ b/common/src/sys/action_state.rs @@ -1,6 +1,6 @@ use crate::{ comp::{ActionState, Attacking, Controller, Gliding, OnGround, Rolling, Vel, Wielding}, - sys::phys::MOVEMENT_THRESHOLD_VEL, + sys::movement::MOVEMENT_THRESHOLD_VEL, }; use specs::{Entities, Join, ReadStorage, System, WriteStorage}; diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index 6507c09f7e..7664b4af8a 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -3,6 +3,7 @@ pub mod agent; pub mod animation; pub mod combat; pub mod controller; +pub mod movement; pub mod phys; mod stats; @@ -14,6 +15,7 @@ const AGENT_SYS: &str = "agent_sys"; const CONTROLLER_SYS: &str = "controller_sys"; const ACTION_STATE_SYS: &str = "action_state_sys"; const PHYS_SYS: &str = "phys_sys"; +const MOVEMENT_SYS: &str = "movement_sys"; const COMBAT_SYS: &str = "combat_sys"; const ANIMATION_SYS: &str = "animation_sys"; const STATS_SYS: &str = "stats_sys"; @@ -22,6 +24,7 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]); dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]); + dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[PHYS_SYS]); dispatch_builder.add( action_state::Sys, ACTION_STATE_SYS, diff --git a/common/src/sys/movement.rs b/common/src/sys/movement.rs new file mode 100644 index 0000000000..a1744d9fa6 --- /dev/null +++ b/common/src/sys/movement.rs @@ -0,0 +1,138 @@ +use crate::{ + comp::{ActionState, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Stats, Vel, Wielding}, + state::DeltaTime, + terrain::TerrainMap, + vol::{ReadVol, Vox}, +}; +use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; +use vek::*; + +const HUMANOID_ACCEL: f32 = 70.0; +const HUMANOID_SPEED: f32 = 120.0; +const HUMANOID_AIR_ACCEL: f32 = 10.0; +const HUMANOID_AIR_SPEED: f32 = 100.0; +const HUMANOID_JUMP_ACCEL: f32 = 16.5; +const ROLL_ACCEL: f32 = 120.0; +const ROLL_SPEED: f32 = 550.0; +const GLIDE_ACCEL: f32 = 15.0; +const GLIDE_SPEED: f32 = 45.0; +// Gravity is 9.81 * 4, so this makes gravity equal to .15 +const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95; + +pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0; + +/// This system applies forces and calculates new positions and velocities. +pub struct Sys; +impl<'a> System<'a> for Sys { + type SystemData = ( + Entities<'a>, + ReadExpect<'a, TerrainMap>, + Read<'a, DeltaTime>, + ReadStorage<'a, MoveDir>, + ReadStorage<'a, Stats>, + ReadStorage<'a, ActionState>, + WriteStorage<'a, Jumping>, + WriteStorage<'a, Wielding>, + WriteStorage<'a, Rolling>, + WriteStorage<'a, OnGround>, + WriteStorage<'a, Pos>, + WriteStorage<'a, Vel>, + WriteStorage<'a, Ori>, + ); + + fn run( + &mut self, + ( + entities, + terrain, + dt, + move_dirs, + stats, + action_states, + mut jumpings, + mut wieldings, + mut rollings, + mut on_grounds, + mut positions, + mut velocities, + mut orientations, + ): Self::SystemData, + ) { + // Apply movement inputs + for (entity, stats, a, move_dir, mut pos, mut vel, mut ori) in ( + &entities, + &stats, + &action_states, + move_dirs.maybe(), + &mut positions, + &mut velocities, + &mut orientations, + ) + .join() + { + // Disable while dead TODO: Replace with client states? + if stats.is_dead { + continue; + } + + // Move player according to move_dir + if let Some(move_dir) = move_dir { + vel.0 += Vec2::broadcast(dt.0) + * move_dir.0 + * match (a.on_ground, a.gliding, a.rolling) { + (true, false, false) + if vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) => + { + HUMANOID_ACCEL + } + (false, true, false) + if vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) => + { + GLIDE_ACCEL + } + (false, false, false) + if vel.0.magnitude_squared() < HUMANOID_AIR_SPEED.powf(2.0) => + { + HUMANOID_AIR_ACCEL + } + (true, false, true) if vel.0.magnitude_squared() < ROLL_SPEED.powf(2.0) => { + ROLL_ACCEL + } + + _ => 0.0, + }; + } + + // Jump + if jumpings.get(entity).is_some() { + vel.0.z = HUMANOID_JUMP_ACCEL; + jumpings.remove(entity); + } + + // Glide + if a.gliding && vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) && vel.0.z < 0.0 { + let _ = wieldings.remove(entity); + let lift = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2; + vel.0.z += dt.0 * lift * Vec2::::from(vel.0 * 0.15).magnitude().min(1.0); + } + + // Roll + if let Some(time) = rollings.get_mut(entity).map(|r| &mut r.time) { + let _ = wieldings.remove(entity); + *time += dt.0; + if *time > 0.55 || !a.moving { + rollings.remove(entity); + } + } + + // Set direction based on velocity when on the ground + if Vec2::::from(vel.0).magnitude_squared() > 0.1 { + ori.0 = Lerp::lerp( + ori.0, + vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0), + 10.0 * dt.0, + ); + } + } + } +} diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index e1c0a8b91d..f196a29f9c 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -10,19 +10,6 @@ use vek::*; const GRAVITY: f32 = 9.81 * 4.0; const FRIC_GROUND: f32 = 0.15; const FRIC_AIR: f32 = 0.015; -const HUMANOID_ACCEL: f32 = 70.0; -const HUMANOID_SPEED: f32 = 120.0; -const HUMANOID_AIR_ACCEL: f32 = 10.0; -const HUMANOID_AIR_SPEED: f32 = 100.0; -const HUMANOID_JUMP_ACCEL: f32 = 16.5; -const ROLL_ACCEL: f32 = 120.0; -const ROLL_SPEED: f32 = 550.0; -const GLIDE_ACCEL: f32 = 15.0; -const GLIDE_SPEED: f32 = 45.0; -// Gravity is 9.81 * 4, so this makes gravity equal to .15 -const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95; - -pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0; // Integrates forces, calculates the new velocity based off of the old velocity // dt = delta time @@ -44,12 +31,7 @@ impl<'a> System<'a> for Sys { Entities<'a>, ReadExpect<'a, TerrainMap>, Read<'a, DeltaTime>, - ReadStorage<'a, MoveDir>, - ReadStorage<'a, Stats>, ReadStorage<'a, ActionState>, - WriteStorage<'a, Jumping>, - WriteStorage<'a, Wielding>, - WriteStorage<'a, Rolling>, WriteStorage<'a, OnGround>, WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, @@ -62,12 +44,7 @@ impl<'a> System<'a> for Sys { entities, terrain, dt, - move_dirs, - stats, action_states, - mut jumpings, - mut wieldings, - mut rollings, mut on_grounds, mut positions, mut velocities, @@ -75,81 +52,15 @@ impl<'a> System<'a> for Sys { ): Self::SystemData, ) { // Apply movement inputs - for (entity, stats, a, move_dir, mut pos, mut vel, mut ori) in ( + for (entity, a, mut pos, mut vel, mut ori) in ( &entities, - &stats, &action_states, - move_dirs.maybe(), &mut positions, &mut velocities, &mut orientations, ) .join() { - // Disable while dead TODO: Replace with client states? - if stats.is_dead { - continue; - } - - // Move player according to move_dir - if let Some(move_dir) = move_dir { - vel.0 += Vec2::broadcast(dt.0) - * move_dir.0 - * match (a.on_ground, a.gliding, a.rolling) { - (true, false, false) - if vel.0.magnitude_squared() < HUMANOID_SPEED.powf(2.0) => - { - HUMANOID_ACCEL - } - (false, true, false) - if vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) => - { - GLIDE_ACCEL - } - (false, false, false) - if vel.0.magnitude_squared() < HUMANOID_AIR_SPEED.powf(2.0) => - { - HUMANOID_AIR_ACCEL - } - (true, false, true) if vel.0.magnitude_squared() < ROLL_SPEED.powf(2.0) => { - ROLL_ACCEL - } - - _ => 0.0, - }; - } - - // Jump - if jumpings.get(entity).is_some() { - vel.0.z = HUMANOID_JUMP_ACCEL; - jumpings.remove(entity); - } - - // Glide - if a.gliding && vel.0.magnitude_squared() < GLIDE_SPEED.powf(2.0) && vel.0.z < 0.0 { - let _ = wieldings.remove(entity); - let lift = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2; - vel.0.z += dt.0 * lift * Vec2::::from(vel.0 * 0.15).magnitude().min(1.0); - } - - // Roll - if let Some(time) = rollings.get_mut(entity).map(|r| &mut r.time) { - let _ = wieldings.remove(entity); - *time += dt.0; - if *time > 0.55 || !a.moving { - rollings.remove(entity); - } - } - - // Set direction based on velocity when on the ground - if Vec2::::from(vel.0).magnitude_squared() > 0.1 { - ori.0 = Lerp::lerp( - ori.0, - vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0), - 10.0 * dt.0, - ); - } - // Integrate forces // Friction is assumed to be a constant dependent on location let friction = 50.0 * if a.on_ground { FRIC_GROUND } else { FRIC_AIR }; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index e5a2bd9f4b..d5723bf2d1 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -130,7 +130,13 @@ lazy_static! { "{}", "/killnpcs : Kill the NPCs", handle_killnpcs, - ), + ), + ChatCommand::new( + "object", + "{}", + "/object : Spawn a random object", + handle_object, + ), ]; } @@ -444,6 +450,27 @@ fn handle_killnpcs(server: &mut Server, entity: EcsEntity, _args: String, _actio server.clients.notify(entity, ServerMsg::Chat(text)); } +fn handle_object(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) { + let pos = server + .state + .ecs() + .read_storage::() + .get(entity) + .copied(); + if let Some(pos) = pos { + server + .create_object(pos, comp::object::Body::random()) + .build(); + server + .clients + .notify(entity, ServerMsg::Chat(format!("Spawned object."))); + } else { + server + .clients + .notify(entity, ServerMsg::Chat(format!("You have no position!"))); + } +} + fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { let opt_alias = scan_fmt!(&args, action.arg_fmt, String); match opt_alias { diff --git a/server/src/lib.rs b/server/src/lib.rs index 6958c62b7e..db753cb97f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -158,6 +158,24 @@ impl Server { .with(comp::ForceUpdate) } + /// Build a static object entity + #[allow(dead_code)] + pub fn create_object( + &mut self, + pos: comp::Pos, + object: comp::object::Body, + ) -> EcsEntityBuilder { + self.state + .ecs_mut() + .create_entity_synced() + .with(pos) + .with(comp::Vel(Vec3::zero())) + .with(comp::Ori(Vec3::unit_y())) + .with(comp::Body::Object(object)) + .with(comp::ActionState::default()) + .with(comp::ForceUpdate) + } + pub fn create_player_character( state: &mut State, entity: EcsEntity, @@ -645,12 +663,12 @@ impl Server { state.write_component(entity, player); // Sync physics - for (&uid, &pos, &vel, &ori, &action_state) in ( + for (&uid, &pos, &vel, &ori, action_state) in ( &state.ecs().read_storage::(), &state.ecs().read_storage::(), &state.ecs().read_storage::(), &state.ecs().read_storage::(), - &state.ecs().read_storage::(), + state.ecs().read_storage::().maybe(), ) .join() { @@ -659,7 +677,7 @@ impl Server { pos, vel, ori, - action_state, + action_state: action_state.copied(), }); } @@ -743,13 +761,13 @@ impl Server { } // Sync physics - for (entity, &uid, &pos, &vel, &ori, &action_state, force_update) in ( + for (entity, &uid, &pos, &vel, &ori, action_state, force_update) in ( &self.state.ecs().entities(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), - &self.state.ecs().read_storage::(), + self.state.ecs().read_storage::().maybe(), self.state.ecs().read_storage::().maybe(), ) .join() @@ -759,7 +777,7 @@ impl Server { pos, vel, ori, - action_state, + action_state: action_state.copied(), }; let state = &self.state; diff --git a/voxygen/src/anim/fixture/mod.rs b/voxygen/src/anim/fixture/mod.rs index 8238f69073..22a2ba2686 100644 --- a/voxygen/src/anim/fixture/mod.rs +++ b/voxygen/src/anim/fixture/mod.rs @@ -1,6 +1,7 @@ use super::Skeleton; use crate::render::FigureBoneData; +#[derive(Clone)] pub struct FixtureSkeleton; impl FixtureSkeleton { diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index cb756fea9e..96df4e6cb7 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -1,5 +1,6 @@ pub mod character; pub mod fixture; +pub mod object; pub mod quadruped; pub mod quadrupedmedium; diff --git a/voxygen/src/anim/object/mod.rs b/voxygen/src/anim/object/mod.rs new file mode 100644 index 0000000000..5ff3f185f5 --- /dev/null +++ b/voxygen/src/anim/object/mod.rs @@ -0,0 +1,39 @@ +use super::Skeleton; +use crate::render::FigureBoneData; +use vek::*; + +#[derive(Clone)] +pub struct ObjectSkeleton; + +impl ObjectSkeleton { + pub fn new() -> Self { + Self {} + } +} + +const SCALE: f32 = 1.0 / 11.0; + +impl Skeleton for ObjectSkeleton { + fn compute_matrices(&self) -> [FigureBoneData; 16] { + [ + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))), + ] + } + + fn interpolate(&mut self, _target: &Self, _dt: f32) {} +} diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 3107744615..13d1849c0e 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -1,6 +1,6 @@ use crate::{ anim::{ - self, character::CharacterSkeleton, quadruped::QuadrupedSkeleton, + self, character::CharacterSkeleton, object::ObjectSkeleton, quadruped::QuadrupedSkeleton, quadrupedmedium::QuadrupedMediumSkeleton, Animation, Skeleton, SkeletonAttr, }, mesh::Meshable, @@ -11,7 +11,7 @@ use crate::{ use client::Client; use common::{ assets, - comp::{self, humanoid, item::Weapon, quadruped, quadruped_medium, Body}, + comp::{self, humanoid, item::Weapon, object, quadruped, quadruped_medium, Body}, figure::Segment, terrain::TerrainChunkSize, vol::VolSize, @@ -105,6 +105,24 @@ impl FigureModelCache { None, None, ], + Body::Object(object) => [ + Some(Self::load_object(object)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ], }; let skeleton_attr = match body { @@ -493,6 +511,18 @@ impl FigureModelCache { Vec3::new(-2.5, -4.0, -2.5), ) } + + fn load_object(obj: object::Body) -> Mesh { + Self::load_mesh( + match obj { + object::Body::Bomb => "object/bomb.vox", + object::Body::Scarecrow => "object/scarecrow.vox", + object::Body::Chest => "object/chest_vines.vox", + object::Body::Pumpkin => "object/pumpkin.vox", + }, + Vec3::new(-3.5, -3.5, 0.0), + ) + } } pub struct FigureMgr { @@ -500,6 +530,7 @@ pub struct FigureMgr { character_states: HashMap>, quadruped_states: HashMap>, quadruped_medium_states: HashMap>, + object_states: HashMap>, } impl FigureMgr { @@ -509,6 +540,7 @@ impl FigureMgr { character_states: HashMap::new(), quadruped_states: HashMap::new(), quadruped_medium_states: HashMap::new(), + object_states: HashMap::new(), } } @@ -534,7 +566,7 @@ impl FigureMgr { &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), - &ecs.read_storage::(), + ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), ) .join() @@ -556,6 +588,9 @@ impl FigureMgr { Body::QuadrupedMedium(_) => { self.quadruped_medium_states.remove(&entity); } + Body::Object(_) => { + self.object_states.remove(&entity); + } } continue; } else if vd_frac > 1.0 { @@ -584,6 +619,11 @@ impl FigureMgr { .entry(entity) .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); + let animation_info = match animation_info { + Some(a_i) => a_i, + None => continue, + }; + let target_skeleton = match animation_info.animation { comp::Animation::Idle => anim::character::IdleAnimation::update_skeleton( state.skeleton_mut(), @@ -654,6 +694,11 @@ impl FigureMgr { .entry(entity) .or_insert_with(|| FigureState::new(renderer, QuadrupedSkeleton::new())); + let animation_info = match animation_info { + Some(a_i) => a_i, + None => continue, + }; + let target_skeleton = match animation_info.animation { comp::Animation::Run => anim::quadruped::RunAnimation::update_skeleton( state.skeleton_mut(), @@ -689,6 +734,11 @@ impl FigureMgr { FigureState::new(renderer, QuadrupedMediumSkeleton::new()) }); + let animation_info = match animation_info { + Some(a_i) => a_i, + None => continue, + }; + let target_skeleton = match animation_info.animation { comp::Animation::Run => { anim::quadrupedmedium::RunAnimation::update_skeleton( @@ -722,6 +772,15 @@ impl FigureMgr { state.skeleton.interpolate(&target_skeleton, dt); state.update(renderer, pos.0, ori.0, col, dt); } + Body::Object(_) => { + let state = self + .object_states + .entry(entity) + .or_insert_with(|| FigureState::new(renderer, ObjectSkeleton::new())); + + state.skeleton = state.skeleton_mut().clone(); + state.update(renderer, pos.0, ori.0, col, dt); + } } } @@ -732,6 +791,8 @@ impl FigureMgr { .retain(|entity, _| ecs.entities().is_alive(*entity)); self.quadruped_medium_states .retain(|entity, _| ecs.entities().is_alive(*entity)); + self.object_states + .retain(|entity, _| ecs.entities().is_alive(*entity)); } pub fn render( @@ -752,25 +813,24 @@ impl FigureMgr { .get(client.entity()) .map_or(Vec3::zero(), |pos| pos.0); - for (entity, _, _, _, body, _, _) in ( + for (entity, _, _, _, body, _) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), - &ecs.read_storage::(), ecs.read_storage::().maybe(), ) .join() // Don't render figures outside the vd - .filter(|(_, pos, _, _, _, _, _)| { + .filter(|(_, pos, _, _, _, _)| { (pos.0 - player_pos) .map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32) .magnitude() < view_distance as f32 }) // Don't render dead entities - .filter(|(_, _, _, _, _, _, stats)| stats.map_or(true, |s| !s.is_dead)) + .filter(|(_, _, _, _, _, stats)| stats.map_or(true, |s| !s.is_dead)) { if let Some((locals, bone_consts)) = match body { Body::Humanoid(_) => self @@ -785,6 +845,10 @@ impl FigureMgr { .quadruped_medium_states .get(&entity) .map(|state| (state.locals(), state.bone_consts())), + Body::Object(_) => self + .object_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), } { let model = &self .model_cache diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 04c1d1cc25..f8c27ba70b 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -117,8 +117,9 @@ impl Scene { // Alter camera position to match player. let tilt = self.camera.get_orientation().y; let dist = self.camera.get_distance(); - self.camera - .set_focus_pos(player_pos + Vec3::unit_z() * (3.0 - tilt.min(0.0) * dist * 0.75)); + self.camera.set_focus_pos( + player_pos + Vec3::unit_z() * (1.2 + dist * 0.15 - tilt.min(0.0) * dist * 0.75), + ); // Tick camera for interpolation. self.camera.update(client.state().get_time());