mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added object entities
This commit is contained in:
parent
56433f0b40
commit
1dc654dde7
@ -403,7 +403,9 @@ impl Client {
|
|||||||
self.state.write_component(entity, pos);
|
self.state.write_component(entity, pos);
|
||||||
self.state.write_component(entity, vel);
|
self.state.write_component(entity, vel);
|
||||||
self.state.write_component(entity, ori);
|
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 } => {
|
ServerMsg::TerrainChunkUpdate { key, chunk } => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod humanoid;
|
pub mod humanoid;
|
||||||
|
pub mod object;
|
||||||
pub mod quadruped;
|
pub mod quadruped;
|
||||||
pub mod quadruped_medium;
|
pub mod quadruped_medium;
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ pub enum Body {
|
|||||||
Humanoid(humanoid::Body),
|
Humanoid(humanoid::Body),
|
||||||
Quadruped(quadruped::Body),
|
Quadruped(quadruped::Body),
|
||||||
QuadrupedMedium(quadruped_medium::Body),
|
QuadrupedMedium(quadruped_medium::Body),
|
||||||
|
Object(object::Body),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Body {
|
impl Component for Body {
|
||||||
|
18
common/src/comp/body/object.rs
Normal file
18
common/src/comp/body/object.rs
Normal file
@ -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];
|
@ -13,7 +13,7 @@ mod stats;
|
|||||||
pub use action_state::ActionState;
|
pub use action_state::ActionState;
|
||||||
pub use agent::Agent;
|
pub use agent::Agent;
|
||||||
pub use animation::{Animation, AnimationInfo};
|
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 controller::Controller;
|
||||||
pub use inputs::{
|
pub use inputs::{
|
||||||
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
||||||
|
@ -40,7 +40,7 @@ pub enum ServerMsg {
|
|||||||
pos: comp::Pos,
|
pos: comp::Pos,
|
||||||
vel: comp::Vel,
|
vel: comp::Vel,
|
||||||
ori: comp::Ori,
|
ori: comp::Ori,
|
||||||
action_state: comp::ActionState,
|
action_state: Option<comp::ActionState>,
|
||||||
},
|
},
|
||||||
TerrainChunkUpdate {
|
TerrainChunkUpdate {
|
||||||
key: Vec2<i32>,
|
key: Vec2<i32>,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{ActionState, Attacking, Controller, Gliding, OnGround, Rolling, Vel, Wielding},
|
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};
|
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ pub mod agent;
|
|||||||
pub mod animation;
|
pub mod animation;
|
||||||
pub mod combat;
|
pub mod combat;
|
||||||
pub mod controller;
|
pub mod controller;
|
||||||
|
pub mod movement;
|
||||||
pub mod phys;
|
pub mod phys;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ const AGENT_SYS: &str = "agent_sys";
|
|||||||
const CONTROLLER_SYS: &str = "controller_sys";
|
const CONTROLLER_SYS: &str = "controller_sys";
|
||||||
const ACTION_STATE_SYS: &str = "action_state_sys";
|
const ACTION_STATE_SYS: &str = "action_state_sys";
|
||||||
const PHYS_SYS: &str = "phys_sys";
|
const PHYS_SYS: &str = "phys_sys";
|
||||||
|
const MOVEMENT_SYS: &str = "movement_sys";
|
||||||
const COMBAT_SYS: &str = "combat_sys";
|
const COMBAT_SYS: &str = "combat_sys";
|
||||||
const ANIMATION_SYS: &str = "animation_sys";
|
const ANIMATION_SYS: &str = "animation_sys";
|
||||||
const STATS_SYS: &str = "stats_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(agent::Sys, AGENT_SYS, &[]);
|
||||||
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]);
|
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]);
|
||||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]);
|
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]);
|
||||||
|
dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[PHYS_SYS]);
|
||||||
dispatch_builder.add(
|
dispatch_builder.add(
|
||||||
action_state::Sys,
|
action_state::Sys,
|
||||||
ACTION_STATE_SYS,
|
ACTION_STATE_SYS,
|
||||||
|
138
common/src/sys/movement.rs
Normal file
138
common/src/sys/movement.rs
Normal file
@ -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::<f32>::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::<f32>::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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,19 +10,6 @@ use vek::*;
|
|||||||
const GRAVITY: f32 = 9.81 * 4.0;
|
const GRAVITY: f32 = 9.81 * 4.0;
|
||||||
const FRIC_GROUND: f32 = 0.15;
|
const FRIC_GROUND: f32 = 0.15;
|
||||||
const FRIC_AIR: f32 = 0.015;
|
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
|
// Integrates forces, calculates the new velocity based off of the old velocity
|
||||||
// dt = delta time
|
// dt = delta time
|
||||||
@ -44,12 +31,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
ReadExpect<'a, TerrainMap>,
|
ReadExpect<'a, TerrainMap>,
|
||||||
Read<'a, DeltaTime>,
|
Read<'a, DeltaTime>,
|
||||||
ReadStorage<'a, MoveDir>,
|
|
||||||
ReadStorage<'a, Stats>,
|
|
||||||
ReadStorage<'a, ActionState>,
|
ReadStorage<'a, ActionState>,
|
||||||
WriteStorage<'a, Jumping>,
|
|
||||||
WriteStorage<'a, Wielding>,
|
|
||||||
WriteStorage<'a, Rolling>,
|
|
||||||
WriteStorage<'a, OnGround>,
|
WriteStorage<'a, OnGround>,
|
||||||
WriteStorage<'a, Pos>,
|
WriteStorage<'a, Pos>,
|
||||||
WriteStorage<'a, Vel>,
|
WriteStorage<'a, Vel>,
|
||||||
@ -62,12 +44,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
entities,
|
entities,
|
||||||
terrain,
|
terrain,
|
||||||
dt,
|
dt,
|
||||||
move_dirs,
|
|
||||||
stats,
|
|
||||||
action_states,
|
action_states,
|
||||||
mut jumpings,
|
|
||||||
mut wieldings,
|
|
||||||
mut rollings,
|
|
||||||
mut on_grounds,
|
mut on_grounds,
|
||||||
mut positions,
|
mut positions,
|
||||||
mut velocities,
|
mut velocities,
|
||||||
@ -75,81 +52,15 @@ impl<'a> System<'a> for Sys {
|
|||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
// Apply movement inputs
|
// 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,
|
&entities,
|
||||||
&stats,
|
|
||||||
&action_states,
|
&action_states,
|
||||||
move_dirs.maybe(),
|
|
||||||
&mut positions,
|
&mut positions,
|
||||||
&mut velocities,
|
&mut velocities,
|
||||||
&mut orientations,
|
&mut orientations,
|
||||||
)
|
)
|
||||||
.join()
|
.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::<f32>::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::<f32>::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
|
// Integrate forces
|
||||||
// Friction is assumed to be a constant dependent on location
|
// Friction is assumed to be a constant dependent on location
|
||||||
let friction = 50.0 * if a.on_ground { FRIC_GROUND } else { FRIC_AIR };
|
let friction = 50.0 * if a.on_ground { FRIC_GROUND } else { FRIC_AIR };
|
||||||
|
@ -131,6 +131,12 @@ lazy_static! {
|
|||||||
"/killnpcs : Kill the NPCs",
|
"/killnpcs : Kill the NPCs",
|
||||||
handle_killnpcs,
|
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));
|
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::<comp::Pos>()
|
||||||
|
.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) {
|
fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||||
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
|
let opt_alias = scan_fmt!(&args, action.arg_fmt, String);
|
||||||
match opt_alias {
|
match opt_alias {
|
||||||
|
@ -158,6 +158,24 @@ impl Server {
|
|||||||
.with(comp::ForceUpdate)
|
.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(
|
pub fn create_player_character(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
@ -645,12 +663,12 @@ impl Server {
|
|||||||
state.write_component(entity, player);
|
state.write_component(entity, player);
|
||||||
|
|
||||||
// Sync physics
|
// Sync physics
|
||||||
for (&uid, &pos, &vel, &ori, &action_state) in (
|
for (&uid, &pos, &vel, &ori, action_state) in (
|
||||||
&state.ecs().read_storage::<Uid>(),
|
&state.ecs().read_storage::<Uid>(),
|
||||||
&state.ecs().read_storage::<comp::Pos>(),
|
&state.ecs().read_storage::<comp::Pos>(),
|
||||||
&state.ecs().read_storage::<comp::Vel>(),
|
&state.ecs().read_storage::<comp::Vel>(),
|
||||||
&state.ecs().read_storage::<comp::Ori>(),
|
&state.ecs().read_storage::<comp::Ori>(),
|
||||||
&state.ecs().read_storage::<comp::ActionState>(),
|
state.ecs().read_storage::<comp::ActionState>().maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
@ -659,7 +677,7 @@ impl Server {
|
|||||||
pos,
|
pos,
|
||||||
vel,
|
vel,
|
||||||
ori,
|
ori,
|
||||||
action_state,
|
action_state: action_state.copied(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,13 +761,13 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sync physics
|
// 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().entities(),
|
||||||
&self.state.ecs().read_storage::<Uid>(),
|
&self.state.ecs().read_storage::<Uid>(),
|
||||||
&self.state.ecs().read_storage::<comp::Pos>(),
|
&self.state.ecs().read_storage::<comp::Pos>(),
|
||||||
&self.state.ecs().read_storage::<comp::Vel>(),
|
&self.state.ecs().read_storage::<comp::Vel>(),
|
||||||
&self.state.ecs().read_storage::<comp::Ori>(),
|
&self.state.ecs().read_storage::<comp::Ori>(),
|
||||||
&self.state.ecs().read_storage::<comp::ActionState>(),
|
self.state.ecs().read_storage::<comp::ActionState>().maybe(),
|
||||||
self.state.ecs().read_storage::<comp::ForceUpdate>().maybe(),
|
self.state.ecs().read_storage::<comp::ForceUpdate>().maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
@ -759,7 +777,7 @@ impl Server {
|
|||||||
pos,
|
pos,
|
||||||
vel,
|
vel,
|
||||||
ori,
|
ori,
|
||||||
action_state,
|
action_state: action_state.copied(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = &self.state;
|
let state = &self.state;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::Skeleton;
|
use super::Skeleton;
|
||||||
use crate::render::FigureBoneData;
|
use crate::render::FigureBoneData;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct FixtureSkeleton;
|
pub struct FixtureSkeleton;
|
||||||
|
|
||||||
impl FixtureSkeleton {
|
impl FixtureSkeleton {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod fixture;
|
pub mod fixture;
|
||||||
|
pub mod object;
|
||||||
pub mod quadruped;
|
pub mod quadruped;
|
||||||
pub mod quadrupedmedium;
|
pub mod quadrupedmedium;
|
||||||
|
|
||||||
|
39
voxygen/src/anim/object/mod.rs
Normal file
39
voxygen/src/anim/object/mod.rs
Normal file
@ -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) {}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
anim::{
|
anim::{
|
||||||
self, character::CharacterSkeleton, quadruped::QuadrupedSkeleton,
|
self, character::CharacterSkeleton, object::ObjectSkeleton, quadruped::QuadrupedSkeleton,
|
||||||
quadrupedmedium::QuadrupedMediumSkeleton, Animation, Skeleton, SkeletonAttr,
|
quadrupedmedium::QuadrupedMediumSkeleton, Animation, Skeleton, SkeletonAttr,
|
||||||
},
|
},
|
||||||
mesh::Meshable,
|
mesh::Meshable,
|
||||||
@ -11,7 +11,7 @@ use crate::{
|
|||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{
|
use common::{
|
||||||
assets,
|
assets,
|
||||||
comp::{self, humanoid, item::Weapon, quadruped, quadruped_medium, Body},
|
comp::{self, humanoid, item::Weapon, object, quadruped, quadruped_medium, Body},
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
terrain::TerrainChunkSize,
|
terrain::TerrainChunkSize,
|
||||||
vol::VolSize,
|
vol::VolSize,
|
||||||
@ -105,6 +105,24 @@ impl FigureModelCache {
|
|||||||
None,
|
None,
|
||||||
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 {
|
let skeleton_attr = match body {
|
||||||
@ -493,6 +511,18 @@ impl FigureModelCache {
|
|||||||
Vec3::new(-2.5, -4.0, -2.5),
|
Vec3::new(-2.5, -4.0, -2.5),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_object(obj: object::Body) -> Mesh<FigurePipeline> {
|
||||||
|
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 {
|
pub struct FigureMgr {
|
||||||
@ -500,6 +530,7 @@ pub struct FigureMgr {
|
|||||||
character_states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
|
character_states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
|
||||||
quadruped_states: HashMap<EcsEntity, FigureState<QuadrupedSkeleton>>,
|
quadruped_states: HashMap<EcsEntity, FigureState<QuadrupedSkeleton>>,
|
||||||
quadruped_medium_states: HashMap<EcsEntity, FigureState<QuadrupedMediumSkeleton>>,
|
quadruped_medium_states: HashMap<EcsEntity, FigureState<QuadrupedMediumSkeleton>>,
|
||||||
|
object_states: HashMap<EcsEntity, FigureState<ObjectSkeleton>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FigureMgr {
|
impl FigureMgr {
|
||||||
@ -509,6 +540,7 @@ impl FigureMgr {
|
|||||||
character_states: HashMap::new(),
|
character_states: HashMap::new(),
|
||||||
quadruped_states: HashMap::new(),
|
quadruped_states: HashMap::new(),
|
||||||
quadruped_medium_states: HashMap::new(),
|
quadruped_medium_states: HashMap::new(),
|
||||||
|
object_states: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,7 +566,7 @@ impl FigureMgr {
|
|||||||
&ecs.read_storage::<comp::Vel>(),
|
&ecs.read_storage::<comp::Vel>(),
|
||||||
&ecs.read_storage::<comp::Ori>(),
|
&ecs.read_storage::<comp::Ori>(),
|
||||||
&ecs.read_storage::<comp::Body>(),
|
&ecs.read_storage::<comp::Body>(),
|
||||||
&ecs.read_storage::<comp::AnimationInfo>(),
|
ecs.read_storage::<comp::AnimationInfo>().maybe(),
|
||||||
ecs.read_storage::<comp::Stats>().maybe(),
|
ecs.read_storage::<comp::Stats>().maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
@ -556,6 +588,9 @@ impl FigureMgr {
|
|||||||
Body::QuadrupedMedium(_) => {
|
Body::QuadrupedMedium(_) => {
|
||||||
self.quadruped_medium_states.remove(&entity);
|
self.quadruped_medium_states.remove(&entity);
|
||||||
}
|
}
|
||||||
|
Body::Object(_) => {
|
||||||
|
self.object_states.remove(&entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if vd_frac > 1.0 {
|
} else if vd_frac > 1.0 {
|
||||||
@ -584,6 +619,11 @@ impl FigureMgr {
|
|||||||
.entry(entity)
|
.entry(entity)
|
||||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
.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 {
|
let target_skeleton = match animation_info.animation {
|
||||||
comp::Animation::Idle => anim::character::IdleAnimation::update_skeleton(
|
comp::Animation::Idle => anim::character::IdleAnimation::update_skeleton(
|
||||||
state.skeleton_mut(),
|
state.skeleton_mut(),
|
||||||
@ -654,6 +694,11 @@ 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 {
|
||||||
|
Some(a_i) => a_i,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
let target_skeleton = match animation_info.animation {
|
let target_skeleton = match animation_info.animation {
|
||||||
comp::Animation::Run => anim::quadruped::RunAnimation::update_skeleton(
|
comp::Animation::Run => anim::quadruped::RunAnimation::update_skeleton(
|
||||||
state.skeleton_mut(),
|
state.skeleton_mut(),
|
||||||
@ -689,6 +734,11 @@ impl FigureMgr {
|
|||||||
FigureState::new(renderer, QuadrupedMediumSkeleton::new())
|
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 {
|
let target_skeleton = match animation_info.animation {
|
||||||
comp::Animation::Run => {
|
comp::Animation::Run => {
|
||||||
anim::quadrupedmedium::RunAnimation::update_skeleton(
|
anim::quadrupedmedium::RunAnimation::update_skeleton(
|
||||||
@ -722,6 +772,15 @@ impl FigureMgr {
|
|||||||
state.skeleton.interpolate(&target_skeleton, dt);
|
state.skeleton.interpolate(&target_skeleton, dt);
|
||||||
state.update(renderer, pos.0, ori.0, col, 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));
|
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||||
self.quadruped_medium_states
|
self.quadruped_medium_states
|
||||||
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||||
|
self.object_states
|
||||||
|
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(
|
||||||
@ -752,25 +813,24 @@ impl FigureMgr {
|
|||||||
.get(client.entity())
|
.get(client.entity())
|
||||||
.map_or(Vec3::zero(), |pos| pos.0);
|
.map_or(Vec3::zero(), |pos| pos.0);
|
||||||
|
|
||||||
for (entity, _, _, _, body, _, _) in (
|
for (entity, _, _, _, body, _) in (
|
||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
&ecs.read_storage::<comp::Pos>(),
|
&ecs.read_storage::<comp::Pos>(),
|
||||||
&ecs.read_storage::<comp::Vel>(),
|
&ecs.read_storage::<comp::Vel>(),
|
||||||
&ecs.read_storage::<comp::Ori>(),
|
&ecs.read_storage::<comp::Ori>(),
|
||||||
&ecs.read_storage::<comp::Body>(),
|
&ecs.read_storage::<comp::Body>(),
|
||||||
&ecs.read_storage::<comp::AnimationInfo>(),
|
|
||||||
ecs.read_storage::<comp::Stats>().maybe(),
|
ecs.read_storage::<comp::Stats>().maybe(),
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
// Don't render figures outside the vd
|
// Don't render figures outside the vd
|
||||||
.filter(|(_, pos, _, _, _, _, _)| {
|
.filter(|(_, pos, _, _, _, _)| {
|
||||||
(pos.0 - player_pos)
|
(pos.0 - player_pos)
|
||||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||||
.magnitude()
|
.magnitude()
|
||||||
< view_distance as f32
|
< view_distance as f32
|
||||||
})
|
})
|
||||||
// Don't render dead entities
|
// 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 {
|
if let Some((locals, bone_consts)) = match body {
|
||||||
Body::Humanoid(_) => self
|
Body::Humanoid(_) => self
|
||||||
@ -785,6 +845,10 @@ impl FigureMgr {
|
|||||||
.quadruped_medium_states
|
.quadruped_medium_states
|
||||||
.get(&entity)
|
.get(&entity)
|
||||||
.map(|state| (state.locals(), state.bone_consts())),
|
.map(|state| (state.locals(), state.bone_consts())),
|
||||||
|
Body::Object(_) => self
|
||||||
|
.object_states
|
||||||
|
.get(&entity)
|
||||||
|
.map(|state| (state.locals(), state.bone_consts())),
|
||||||
} {
|
} {
|
||||||
let model = &self
|
let model = &self
|
||||||
.model_cache
|
.model_cache
|
||||||
|
@ -117,8 +117,9 @@ impl Scene {
|
|||||||
// Alter camera position to match player.
|
// Alter camera position to match player.
|
||||||
let tilt = self.camera.get_orientation().y;
|
let tilt = self.camera.get_orientation().y;
|
||||||
let dist = self.camera.get_distance();
|
let dist = self.camera.get_distance();
|
||||||
self.camera
|
self.camera.set_focus_pos(
|
||||||
.set_focus_pos(player_pos + Vec3::unit_z() * (3.0 - tilt.min(0.0) * dist * 0.75));
|
player_pos + Vec3::unit_z() * (1.2 + dist * 0.15 - tilt.min(0.0) * dist * 0.75),
|
||||||
|
);
|
||||||
|
|
||||||
// Tick camera for interpolation.
|
// Tick camera for interpolation.
|
||||||
self.camera.update(client.state().get_time());
|
self.camera.update(client.state().get_time());
|
||||||
|
Loading…
Reference in New Issue
Block a user