Removes input sys, moves code to combat and phys

This commit is contained in:
Cody 2019-06-11 15:28:25 -04:00 committed by timokoesters
parent b947d78dac
commit 1f6c1188bc
No known key found for this signature in database
GPG Key ID: CD80BE9AAEE78097
7 changed files with 191 additions and 768 deletions

View File

@ -1,4 +1,4 @@
use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
use specs::{Component, FlaggedStorage, VecStorage};
use vek::*;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]

80
common/src/sys/combat.rs Normal file
View File

@ -0,0 +1,80 @@
use crate::{
comp::{
phys::{ForceUpdate, Ori, Pos, Vel},
Attacking, HealthSource, Stats,
},
state::{DeltaTime, Uid},
};
use log::warn;
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
/// This system is responsible for handling accepted inputs like moving or attacking
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
ReadStorage<'a, Uid>,
Read<'a, DeltaTime>,
ReadStorage<'a, Pos>,
WriteStorage<'a, Vel>,
ReadStorage<'a, Ori>,
WriteStorage<'a, Attacking>,
WriteStorage<'a, Stats>,
WriteStorage<'a, ForceUpdate>,
);
fn run(
&mut self,
(
entities,
uids,
dt,
positions,
mut velocities,
orientations,
mut attackings,
mut stats,
mut force_updates,
): Self::SystemData,
) {
// Attacks
(&entities, &uids, &positions, &orientations, &mut attackings)
.join()
.filter_map(|(entity, uid, pos, ori, mut attacking)| {
if !attacking.applied {
// Go through all other entities
for (b, pos_b, mut vel_b, mut stat_b) in
(&entities, &positions, &mut velocities, &mut stats).join()
{
// Check if it is a hit
if entity != b
&& !stat_b.is_dead
&& pos.0.distance_squared(pos_b.0) < 50.0
&& ori.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
{
// Deal damage
stat_b.hp.change_by(-10, HealthSource::Attack { by: *uid }); // TODO: variable damage and weapon
vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0;
vel_b.0.z = 15.0;
if let Err(err) = force_updates.insert(b, ForceUpdate) {
warn!("Inserting ForceUpdate for an entity failed: {:?}", err);
}
}
}
attacking.applied = true;
}
if attacking.time > 0.5 {
Some(entity)
} else {
attacking.time += dt.0;
None
}
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|e| {
attackings.remove(e);
});
}
}

View File

@ -1,16 +1,11 @@
use crate::{
comp::{
phys::{ForceUpdate, Ori, Pos, Vel},
Animation, AnimationInfo, Attacking, Controller, Gliding, HealthSource, Jumping, MoveDir,
OnGround, Respawning, Stats,
Attacking, Controller, Gliding, Jumping, MoveDir, OnGround, Respawning, Stats,
},
state::{DeltaTime, Uid},
terrain::TerrainMap,
vol::{ReadVol, Vox},
state::DeltaTime,
};
use log::warn;
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
use vek::*;
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
/// This system is responsible for validating controller inputs
pub struct Sys;
@ -20,7 +15,6 @@ impl<'a> System<'a> for Sys {
Read<'a, DeltaTime>,
ReadStorage<'a, Controller>,
ReadStorage<'a, Stats>,
ReadExpect<'a, TerrainMap>,
ReadStorage<'a, Pos>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Ori>,
@ -40,7 +34,6 @@ impl<'a> System<'a> for Sys {
dt,
controllers,
stats,
terrain,
positions,
mut velocities,
mut orientations,
@ -50,10 +43,21 @@ impl<'a> System<'a> for Sys {
mut attackings,
mut respawns,
mut glidings,
mut force_updates,
force_updates,
): Self::SystemData,
) {
for (entity, controller, stats, pos, mut vel, mut ori, on_ground) in (
for (
entity,
controller,
stats,
pos,
mut vel,
mut ori,
on_ground,
mut attacking,
mut jumping,
mut gliding,
) in (
&entities,
&controllers,
&stats,
@ -61,6 +65,9 @@ impl<'a> System<'a> for Sys {
&mut velocities,
&mut orientations,
on_grounds.maybe(),
attackings.maybe(),
jumpings.maybe(),
glidings.maybe(),
)
.join()
{
@ -73,10 +80,10 @@ impl<'a> System<'a> for Sys {
}
// Glide
if controller.glide && on_ground.is_none() && attackings.get(entity).is_none() {
glidings.insert(entity, Gliding);
if controller.glide && on_ground.is_none() && attacking.is_none() {
gliding = Some(&Gliding);
} else {
glidings.remove(entity);
gliding = None
}
// Move dir
@ -90,18 +97,15 @@ impl<'a> System<'a> for Sys {
);
// Attack
if controller.attack
&& attackings.get(entity).is_none()
&& glidings.get(entity).is_none()
{
attackings.insert(entity, Attacking::start());
if controller.attack && attacking.is_none() && gliding.is_none() {
attacking = Some(&Attacking::start());
}
// Jump
if on_grounds.get(entity).is_some() && controller.jump && vel.0.z <= 0.0 {
jumpings.insert(entity, Jumping);
if on_ground.is_some() && controller.jump && vel.0.z <= 0.0 {
jumping = Some(&Jumping);
} else {
jumpings.remove(entity);
jumping = None;
}
}
}

View File

@ -1,151 +0,0 @@
use crate::{
comp::{
phys::{ForceUpdate, Ori, Pos, Vel},
Animation, AnimationInfo, Attacking, Gliding, HealthSource, Jumping, MoveDir, OnGround,
Respawning, Stats,
},
state::{DeltaTime, Uid},
terrain::TerrainMap,
vol::{ReadVol, Vox},
};
use log::warn;
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
use vek::*;
const HUMANOID_ACCEL: f32 = 100.0;
const HUMANOID_SPEED: f32 = 500.0;
const HUMANOID_AIR_ACCEL: f32 = 10.0;
const HUMANOID_AIR_SPEED: f32 = 100.0;
const HUMANOID_JUMP_ACCEL: f32 = 16.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;
/// This system is responsible for handling accepted inputs like moving or attacking
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
ReadStorage<'a, Uid>,
Read<'a, DeltaTime>,
ReadExpect<'a, TerrainMap>,
ReadStorage<'a, Pos>,
ReadStorage<'a, OnGround>,
ReadStorage<'a, MoveDir>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Ori>,
WriteStorage<'a, AnimationInfo>,
WriteStorage<'a, Stats>,
WriteStorage<'a, Respawning>,
WriteStorage<'a, Jumping>,
WriteStorage<'a, Gliding>,
WriteStorage<'a, Attacking>,
WriteStorage<'a, ForceUpdate>,
);
fn run(
&mut self,
(
entities,
uids,
dt,
terrain,
positions,
on_grounds,
move_dirs,
mut velocities,
mut orientations,
mut animation_infos,
mut stats,
mut respawnings,
mut jumpings,
glidings,
mut attackings,
mut force_updates,
): Self::SystemData,
) {
// Attacks
(&entities, &uids, &positions, &orientations, &mut attackings)
.join()
.filter_map(|(entity, uid, pos, ori, mut attacking)| {
if !attacking.applied {
// Go through all other entities
for (b, pos_b, stat_b, mut vel_b) in
(&entities, &positions, &mut stats, &mut velocities).join()
{
// Check if it is a hit
if entity != b
&& !stat_b.is_dead
&& pos.0.distance_squared(pos_b.0) < 50.0
&& ori.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
{
// Deal damage
stat_b.hp.change_by(-10, HealthSource::Attack { by: *uid }); // TODO: variable damage and weapon
vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0;
vel_b.0.z = 15.0;
if let Err(err) = force_updates.insert(b, ForceUpdate) {
warn!("Inserting ForceUpdate for an entity failed: {:?}", err);
}
}
}
attacking.applied = true;
}
if attacking.time > 0.5 {
Some(entity)
} else {
attacking.time += dt.0;
None
}
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|e| {
attackings.remove(e);
});
// Apply movement inputs
for (entity, mut vel, mut ori, on_ground, move_dir, jumping, gliding) in (
&entities,
&mut velocities,
&mut orientations,
on_grounds.maybe(),
move_dirs.maybe(),
jumpings.maybe(),
glidings.maybe(),
)
.join()
{
// Move player according to move_dir
if let Some(move_dir) = move_dir {
vel.0 += Vec2::broadcast(dt.0)
* move_dir.0
* match (on_ground.is_some(), gliding.is_some()) {
(true, false) if vel.0.magnitude() < HUMANOID_SPEED => HUMANOID_ACCEL,
(false, true) if vel.0.magnitude() < GLIDE_SPEED => GLIDE_ACCEL,
(false, false) if vel.0.magnitude() < HUMANOID_AIR_SPEED => {
HUMANOID_AIR_ACCEL
}
_ => 0.0,
};
}
// Jump
if jumping.is_some() {
vel.0.z = HUMANOID_JUMP_ACCEL;
}
// Glide
if gliding.is_some() && vel.0.magnitude() < GLIDE_SPEED && vel.0.z < 0.0 {
let anti_grav = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
vel.0.z += dt.0 * anti_grav * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
}
// Set direction based on velocity
if vel.0.magnitude_squared() != 0.0 {
ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
}
}
}
}

View File

@ -1,7 +1,7 @@
pub mod agent;
pub mod animation;
pub mod combat;
pub mod controller;
pub mod inputs;
pub mod phys;
mod stats;
@ -12,7 +12,7 @@ use specs::DispatcherBuilder;
const AGENT_SYS: &str = "agent_sys";
const CONTROLLER_SYS: &str = "controller_sys";
const PHYS_SYS: &str = "phys_sys";
const INPUTS_SYS: &str = "inputs_sys";
const COMBAT_SYS: &str = "combat_sys";
const ANIMATION_SYS: &str = "animation_sys";
const STATS_SYS: &str = "stats_sys";
@ -20,7 +20,7 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[]);
dispatch_builder.add(phys::Sys, PHYS_SYS, &[]);
dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]);
dispatch_builder.add(combat::Sys, COMBAT_SYS, &[]);
dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]);
dispatch_builder.add(stats::Sys, STATS_SYS, &[INPUTS_SYS]);
dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]);
}

View File

@ -1,7 +1,7 @@
use crate::{
comp::{
phys::{Pos, Vel},
OnGround, Stats,
phys::{Ori, Pos, Vel},
Gliding, Jumping, MoveDir, OnGround, Stats,
},
state::DeltaTime,
terrain::TerrainMap,
@ -13,6 +13,15 @@ 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 = 100.0;
const HUMANOID_SPEED: f32 = 500.0;
const HUMANOID_AIR_ACCEL: f32 = 10.0;
const HUMANOID_AIR_SPEED: f32 = 100.0;
const HUMANOID_JUMP_ACCEL: f32 = 16.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;
// Integrates forces, calculates the new velocity based off of the old velocity
// dt = delta time
@ -35,30 +44,89 @@ fn integrate_forces(dt: f32, mut lv: Vec3<f32>, damp: f32) -> Vec3<f32> {
lv
}
/// This system applies forces and calculates new positions and velocities
/// 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, Stats>,
WriteStorage<'a, OnGround>,
WriteStorage<'a, Pos>,
WriteStorage<'a, Vel>,
WriteStorage<'a, OnGround>,
WriteStorage<'a, Ori>,
ReadStorage<'a, MoveDir>,
ReadStorage<'a, Jumping>,
ReadStorage<'a, Gliding>,
WriteStorage<'a, Stats>,
);
fn run(
&mut self,
(entities, terrain, dt, stats, mut positions, mut velocities, mut on_grounds): Self::SystemData,
(
entities,
terrain,
dt,
mut on_grounds,
mut positions,
mut velocities,
mut orientations,
move_dirs,
jumpings,
glidings,
stats,
): Self::SystemData,
) {
for (entity, stats, pos, vel) in (&entities, &stats, &mut positions, &mut velocities).join()
// Apply movement inputs
for (entity, mut pos, mut vel, mut ori, mut on_ground, move_dir, jumping, gliding, stats) in
(
&entities,
&mut positions,
&mut velocities,
&mut orientations,
on_grounds.maybe(),
move_dirs.maybe(),
jumpings.maybe(),
glidings.maybe(),
&stats,
)
.join()
{
// Disable while dead TODO: Replace with client states
// 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 (on_ground.is_some(), gliding.is_some()) {
(true, false) if vel.0.magnitude() < HUMANOID_SPEED => HUMANOID_ACCEL,
(false, true) if vel.0.magnitude() < GLIDE_SPEED => GLIDE_ACCEL,
(false, false) if vel.0.magnitude() < HUMANOID_AIR_SPEED => {
HUMANOID_AIR_ACCEL
}
_ => 0.0,
};
}
// Jump
if jumping.is_some() {
vel.0.z = HUMANOID_JUMP_ACCEL;
}
// Glide
if gliding.is_some() && vel.0.magnitude() < GLIDE_SPEED && vel.0.z < 0.0 {
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);
}
// Set direction based on velocity
if vel.0.magnitude_squared() != 0.0 {
ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
}
// Movement
pos.0 += vel.0 * dt.0;
@ -69,15 +137,15 @@ impl<'a> System<'a> for Sys {
.unwrap_or(false)
&& vel.0.z <= 0.0
{
on_grounds.insert(entity, OnGround);
on_ground = Some(&OnGround);
} else {
on_grounds.remove(entity);
on_ground = None;
}
// Integrate forces
// Friction is assumed to be a constant dependent on location
let friction = 50.0
* if on_grounds.get(entity).is_some() {
* if on_ground.is_some() {
FRIC_GROUND
} else {
FRIC_AIR

578
diff
View File

@ -1,578 +0,0 @@
diff --git a/chat-cli/src/main.rs b/chat-cli/src/main.rs
index f68a5b4..8ebd46f 100644
--- a/chat-cli/src/main.rs
+++ b/chat-cli/src/main.rs
@@ -29,7 +29,7 @@ fn main() {
client.send_chat("Hello!".to_string());
loop {
- let events = match client.tick(comp::Control::default(), clock.get_last_delta()) {
+ let events = match client.tick(comp::Controller::default(), clock.get_last_delta()) {
Ok(events) => events,
Err(err) => {
error!("Error: {:?}", err);
diff --git a/client/src/lib.rs b/client/src/lib.rs
index f491359..ee3b62e 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -154,52 +154,6 @@ impl Client {
self.postbox.send_message(ClientMsg::Chat(msg))
}
- /// Jump locally, the new positions will be synced to the server
- #[allow(dead_code)]
- pub fn jump(&mut self) {
- if self.client_state != ClientState::Character {
- return;
- }
- self.state.write_component(self.entity, comp::Jumping);
- }
-
- /// Start to glide locally, animation will be synced
- #[allow(dead_code)]
- pub fn glide(&mut self, state: bool) {
- if self.client_state != ClientState::Character {
- return;
- }
- if state {
- self.state.write_component(self.entity, comp::Gliding);
- } else {
- self.state
- .ecs_mut()
- .write_storage::<comp::Gliding>()
- .remove(self.entity);
- }
- }
-
- /// Start to attack
- #[allow(dead_code)]
- pub fn attack(&mut self) {
- if self.client_state != ClientState::Character {
- return;
- }
- // TODO: Test if attack is possible using timeout
- self.state
- .write_component(self.entity, comp::Attacking::start());
- self.postbox.send_message(ClientMsg::Attack);
- }
-
- /// Tell the server the client wants to respawn.
- #[allow(dead_code)]
- pub fn respawn(&mut self) {
- if self.client_state != ClientState::Dead {
- return;
- }
- self.postbox.send_message(ClientMsg::Respawn)
- }
-
/// Remove all cached terrain
#[allow(dead_code)]
pub fn clear_terrain(&mut self) {
@@ -209,7 +163,7 @@ impl Client {
/// Execute a single client tick, handle input and update the game state by the given duration.
#[allow(dead_code)]
- pub fn tick(&mut self, control: comp::Control, dt: Duration) -> Result<Vec<Event>, Error> {
+ pub fn tick(&mut self, controller: comp::Controller, dt: Duration) -> Result<Vec<Event>, Error> {
// This tick function is the centre of the Veloren universe. Most client-side things are
// managed from here, and as such it's important that it stays organised. Please consult
// the core developers before making significant changes to this code. Here is the
@@ -226,10 +180,8 @@ impl Client {
// 1) Handle input from frontend.
// Pass character actions from frontend input to the player's entity.
- // TODO: Only do this if the entity already has a Inputs component!
- if self.client_state == ClientState::Character {
- self.state.write_component(self.entity, control.clone());
- }
+ self.state.write_component(self.entity, controller.clone());
+ self.postbox.send_message(ClientMsg::Controller(controller));
// 2) Build up a list of events for this frame, to be passed to the frontend.
let mut frontend_events = Vec::new();
diff --git a/common/src/comp/inputs.rs b/common/src/comp/inputs.rs
index ce55110..27b7b75 100644
--- a/common/src/comp/inputs.rs
+++ b/common/src/comp/inputs.rs
@@ -1,11 +1,6 @@
use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
use vek::*;
-#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
-pub struct Control {
- pub move_dir: Vec2<f32>,
-}
-
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Respawning;
@@ -14,16 +9,13 @@ pub struct Attacking {
pub time: f32,
pub applied: bool,
}
+
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Jumping;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Gliding;
-impl Component for Control {
- type Storage = VecStorage<Self>;
-}
-
impl Component for Respawning {
type Storage = NullStorage<Self>;
}
@@ -36,6 +28,7 @@ impl Attacking {
}
}
}
+
impl Component for Attacking {
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}
diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs
index ee351db..2ca2e12 100644
--- a/common/src/comp/mod.rs
+++ b/common/src/comp/mod.rs
@@ -2,6 +2,7 @@ pub mod actor;
pub mod agent;
pub mod animation;
pub mod inputs;
+pub mod controller;
pub mod phys;
pub mod player;
pub mod stats;
@@ -15,8 +16,8 @@ pub use actor::QuadrupedMediumBody;
pub use agent::Agent;
pub use animation::Animation;
pub use animation::AnimationInfo;
+pub use controller::Controller;
pub use inputs::Attacking;
-pub use inputs::Control;
pub use inputs::Gliding;
pub use inputs::Jumping;
pub use inputs::Respawning;
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index aa765d0..1187831 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -11,8 +11,7 @@ pub enum ClientMsg {
name: String,
body: comp::Body,
},
- Attack,
- Respawn,
+ Controller(comp::Controller),
RequestState(ClientState),
SetViewDistance(u32),
Ping,
diff --git a/common/src/state.rs b/common/src/state.rs
index 9357c60..630f7c8 100644
--- a/common/src/state.rs
+++ b/common/src/state.rs
@@ -110,9 +110,9 @@ impl State {
ecs.register::<comp::phys::Vel>();
ecs.register::<comp::phys::Ori>();
ecs.register::<comp::AnimationInfo>();
+ ecs.register::<comp::Controller>();
// Register client-local components
- ecs.register::<comp::Control>();
ecs.register::<comp::Jumping>();
// Register server-local components
diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs
index 55e845c..0e5e2f8 100644
--- a/common/src/sys/agent.rs
+++ b/common/src/sys/agent.rs
@@ -1,4 +1,4 @@
-use crate::comp::{phys::Pos, Agent, Attacking, Control, Jumping};
+use crate::comp::{phys::Pos, Agent, Attacking, Controller, Jumping};
use log::warn;
use rand::{seq::SliceRandom, thread_rng};
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
@@ -12,17 +12,17 @@ impl<'a> System<'a> for Sys {
Entities<'a>,
WriteStorage<'a, Agent>,
ReadStorage<'a, Pos>,
- WriteStorage<'a, Control>,
+ WriteStorage<'a, Controller>,
WriteStorage<'a, Jumping>,
WriteStorage<'a, Attacking>,
);
fn run(
&mut self,
- (entities, mut agents, positions, mut controls, mut jumps, mut attacks): Self::SystemData,
+ (entities, mut agents, positions, mut controllers, mut jumps, mut attacks): Self::SystemData,
) {
- for (entity, agent, pos, control) in
- (&entities, &mut agents, &positions, &mut controls).join()
+ for (entity, agent, pos, controller) in
+ (&entities, &mut agents, &positions, &mut controllers).join()
{
match agent {
Agent::Wanderer(bearing) => {
@@ -32,7 +32,7 @@ impl<'a> System<'a> for Sys {
- pos.0 * 0.0002;
if bearing.magnitude_squared() != 0.0 {
- control.move_dir = bearing.normalized();
+ controller.move_dir = bearing.normalized();
}
}
Agent::Pet { target, offset } => {
@@ -49,7 +49,7 @@ impl<'a> System<'a> for Sys {
// Move towards the target.
let dist: f32 = Vec2::from(tgt_pos - pos.0).magnitude();
- control.move_dir = if dist > 5.0 {
+ controller.move_dir = if dist > 5.0 {
Vec2::from(tgt_pos - pos.0).normalized()
} else if dist < 1.5 && dist > 0.0 {
Vec2::from(pos.0 - tgt_pos).normalized()
@@ -57,7 +57,7 @@ impl<'a> System<'a> for Sys {
Vec2::zero()
};
}
- _ => control.move_dir = Vec2::zero(),
+ _ => controller.move_dir = Vec2::zero(),
}
// Change offset occasionally.
@@ -72,7 +72,7 @@ impl<'a> System<'a> for Sys {
Some(tgt_pos) => {
let dist = Vec2::<f32>::from(tgt_pos.0 - pos.0).magnitude();
if dist < 2.0 {
- control.move_dir = Vec2::zero();
+ controller.move_dir = Vec2::zero();
if rand::random::<f32>() < 0.2 {
attacks
@@ -82,7 +82,7 @@ impl<'a> System<'a> for Sys {
false
} else if dist < 60.0 {
- control.move_dir =
+ controller.move_dir =
Vec2::<f32>::from(tgt_pos.0 - pos.0).normalized() * 0.96;
false
@@ -91,7 +91,7 @@ impl<'a> System<'a> for Sys {
}
}
None => {
- control.move_dir = Vec2::one();
+ controller.move_dir = Vec2::one();
true
}
};
diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs
index 288a0e0..6cadba5 100644
--- a/common/src/sys/inputs.rs
+++ b/common/src/sys/inputs.rs
@@ -1,7 +1,7 @@
use crate::{
comp::{
phys::{ForceUpdate, Ori, Pos, Vel},
- Animation, AnimationInfo, Attacking, Control, Gliding, HealthSource, Jumping, Stats,
+ Animation, AnimationInfo, Attacking, Controller, Gliding, HealthSource, Jumping, Stats,
},
state::{DeltaTime, Uid},
terrain::TerrainMap,
@@ -13,17 +13,6 @@ use vek::*;
// Basic ECS AI agent system
pub struct Sys;
-
-const HUMANOID_ACCEL: f32 = 100.0;
-const HUMANOID_SPEED: f32 = 500.0;
-const HUMANOID_AIR_ACCEL: f32 = 10.0;
-const HUMANOID_AIR_SPEED: f32 = 100.0;
-const HUMANOID_JUMP_ACCEL: f32 = 16.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;
-
impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
@@ -35,7 +24,7 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Ori>,
WriteStorage<'a, AnimationInfo>,
WriteStorage<'a, Stats>,
- ReadStorage<'a, Control>,
+ ReadStorage<'a, Controller>,
WriteStorage<'a, Jumping>,
WriteStorage<'a, Gliding>,
WriteStorage<'a, Attacking>,
@@ -54,67 +43,31 @@ impl<'a> System<'a> for Sys {
mut orientations,
mut animation_infos,
mut stats,
- controls,
+ controllers,
mut jumps,
glides,
mut attacks,
mut force_updates,
): Self::SystemData,
) {
- for (entity, pos, control, stats, mut ori, mut vel) in (
+ for (entity, pos, controller, stats, mut ori, mut vel) in (
&entities,
&positions,
- &controls,
+ &controllers,
&stats,
&mut orientations,
&mut velocities,
)
.join()
{
- // Disable while dead TODO: Replace with client states
- if stats.is_dead {
- continue;
- }
-
let on_ground = terrain
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
.map(|vox| !vox.is_empty())
.unwrap_or(false)
&& vel.0.z <= 0.0;
- let gliding = glides.get(entity).is_some() && vel.0.z < 0.0;
- let move_dir = if control.move_dir.magnitude() > 1.0 {
- control.move_dir.normalized()
- } else {
- control.move_dir
- };
-
- if on_ground {
- // Move player according to move_dir
- if vel.0.magnitude() < HUMANOID_SPEED {
- vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_ACCEL;
- }
-
- // Jump
- if jumps.get(entity).is_some() && vel.0.z <= 0.0 {
- vel.0.z = HUMANOID_JUMP_ACCEL;
- jumps.remove(entity);
- }
- } else if gliding && vel.0.magnitude() < GLIDE_SPEED {
- let anti_grav = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2;
- vel.0.z += dt.0 * anti_grav * Vec2::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
- vel.0 += Vec2::broadcast(dt.0) * move_dir * GLIDE_ACCEL;
- } else if vel.0.magnitude() < HUMANOID_AIR_SPEED {
- vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_AIR_ACCEL;
- }
-
- // Set direction based on velocity
- if vel.0.magnitude_squared() != 0.0 {
- ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
- }
-
let animation = if on_ground {
- if control.move_dir.magnitude() > 0.01 {
+ if controller.move_dir.magnitude() > 0.01 {
Animation::Run
} else if attacks.get(entity).is_some() {
Animation::Attack
@@ -149,6 +102,7 @@ impl<'a> System<'a> for Sys {
(&entities, &uids, &positions, &orientations, &mut attacks).join()
{
if !attacking.applied {
+ dbg!();
for (b, pos_b, stat_b, mut vel_b) in
(&entities, &positions, &mut stats, &mut velocities).join()
{
diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs
index da6f629..e6a5917 100644
--- a/common/src/sys/mod.rs
+++ b/common/src/sys/mod.rs
@@ -1,6 +1,7 @@
pub mod actions;
pub mod agent;
pub mod animation;
+pub mod controller;
pub mod inputs;
pub mod phys;
mod stats;
@@ -10,6 +11,7 @@ use specs::DispatcherBuilder;
// System names
const AGENT_SYS: &str = "agent_sys";
+const CONTROLLER_SYS: &str = "controller_sys";
const INPUTS_SYS: &str = "inputs_sys";
const ACTIONS_SYS: &str = "actions_sys";
const PHYS_SYS: &str = "phys_sys";
@@ -20,6 +22,7 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
dispatch_builder.add(phys::Sys, PHYS_SYS, &[]);
dispatch_builder.add(actions::Sys, ACTIONS_SYS, &[]);
+ dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[]);
dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]);
dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]);
dispatch_builder.add(stats::Sys, STATS_SYS, &[INPUTS_SYS]);
diff --git a/server/src/lib.rs b/server/src/lib.rs
index ead806c..6260f0a 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -145,7 +145,7 @@ impl Server {
.with(pos)
.with(comp::phys::Vel(Vec3::zero()))
.with(comp::phys::Ori(Vec3::unit_y()))
- .with(comp::Control::default())
+ .with(comp::Controller::default())
.with(comp::AnimationInfo::default())
.with(comp::Actor::Character { name, body })
.with(comp::Stats::default())
@@ -164,6 +164,7 @@ impl Server {
state.write_component(entity, comp::Actor::Character { name, body });
state.write_component(entity, comp::Stats::default());
state.write_component(entity, comp::AnimationInfo::default());
+ state.write_component(entity, comp::Controller::default());
state.write_component(entity, comp::phys::Pos(spawn_point));
state.write_component(entity, comp::phys::Vel(Vec3::zero()));
state.write_component(entity, comp::phys::Ori(Vec3::unit_y()));
@@ -492,25 +493,16 @@ impl Server {
}
ClientState::Pending => {}
},
- ClientMsg::Attack => match client.client_state {
- ClientState::Character => {
- if state
- .ecs()
- .read_storage::<comp::Attacking>()
- .get(entity)
- .is_none()
- {
- state.write_component(entity, comp::Attacking::start());
- }
+ ClientMsg::Controller(controller) => match client.client_state {
+ ClientState::Connected | ClientState::Registered | ClientState::Spectator => {
+ client.error_state(RequestStateError::Impossible)
}
- _ => client.error_state(RequestStateError::Impossible),
- },
- ClientMsg::Respawn => match client.client_state {
- ClientState::Dead => {
- state.write_component(entity, comp::Respawning);
+ ClientState::Dead
+ | ClientState::Character => {
+ state.write_component(entity, controller);
}
- _ => client.error_state(RequestStateError::Impossible),
- },
+ ClientState::Pending => {}
+ }
ClientMsg::Chat(msg) => match client.client_state {
ClientState::Connected => {
client.error_state(RequestStateError::Impossible)
diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs
index 2192ce7..1a3e3e3 100644
--- a/voxygen/src/menu/char_selection/mod.rs
+++ b/voxygen/src/menu/char_selection/mod.rs
@@ -110,7 +110,7 @@ impl PlayState for CharSelectionState {
if let Err(err) = self
.client
.borrow_mut()
- .tick(comp::Control::default(), clock.get_last_delta())
+ .tick(comp::Controller::default(), clock.get_last_delta())
{
error!("Failed to tick the scene: {:?}", err);
return PlayStateResult::Pop;
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index 913e421..bd5d876 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -18,8 +18,9 @@ const FPS: u64 = 60;
pub struct SessionState {
scene: Scene,
client: Rc<RefCell<Client>>,
- key_state: KeyState,
hud: Hud,
+ key_state: KeyState,
+ controller: comp::Controller,
}
/// Represents an active game session (i.e., the one being played).
@@ -32,6 +33,7 @@ impl SessionState {
scene,
client,
key_state: KeyState::new(),
+ controller: comp::Controller::default(),
hud: Hud::new(window),
}
}
@@ -47,21 +49,11 @@ const BG_COLOR: Rgba<f32> = Rgba {
impl SessionState {
/// Tick the session (and the client attached to it).
- pub fn tick(&mut self, dt: Duration) -> Result<(), Error> {
- // Calculate the movement input vector of the player from the current key presses
- // and the camera direction.
- let ori = self.scene.camera().get_orientation();
- let unit_vecs = (
- Vec2::new(ori[0].cos(), -ori[0].sin()),
- Vec2::new(ori[0].sin(), ori[0].cos()),
- );
- let dir_vec = self.key_state.dir_vec();
- let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
-
+ fn tick(&mut self, dt: Duration) -> Result<(), Error> {
for event in self
.client
.borrow_mut()
- .tick(comp::Control { move_dir }, dt)?
+ .tick(self.controller.clone(), dt)?
{
match event {
client::Event::Chat(msg) => {
@@ -121,19 +113,19 @@ impl PlayState for SessionState {
Event::Close => {
return PlayStateResult::Shutdown;
}
- Event::InputUpdate(GameInput::Attack, true) => {
- self.client.borrow_mut().attack();
- self.client.borrow_mut().respawn();
+ Event::InputUpdate(GameInput::Attack, state) => {
+ self.controller.attack = state;
+ self.controller.respawn = state; // TODO: Don't do both
}
- Event::InputUpdate(GameInput::Jump, true) => {
- self.client.borrow_mut().jump();
+ Event::InputUpdate(GameInput::Jump, state) => {
+ self.controller.jump = state;
}
Event::InputUpdate(GameInput::MoveForward, state) => self.key_state.up = state,
Event::InputUpdate(GameInput::MoveBack, state) => self.key_state.down = state,
Event::InputUpdate(GameInput::MoveLeft, state) => self.key_state.left = state,
Event::InputUpdate(GameInput::MoveRight, state) => self.key_state.right = state,
Event::InputUpdate(GameInput::Glide, state) => {
- self.client.borrow_mut().glide(state)
+ self.controller.glide = state;
}
// Pass all other events to the scene
@@ -143,6 +135,17 @@ impl PlayState for SessionState {
}
}
+ // Calculate the movement input vector of the player from the current key presses
+ // and the camera direction.
+ let ori = self.scene.camera().get_orientation();
+ let unit_vecs = (
+ Vec2::new(ori[0].cos(), -ori[0].sin()),
+ Vec2::new(ori[0].sin(), ori[0].cos()),
+ );
+ let dir_vec = self.key_state.dir_vec();
+ self.controller.move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
+
+
// Perform an in-game tick.
if let Err(err) = self.tick(clock.get_last_delta()) {
error!("Failed to tick the scene: {:?}", err);