mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Improve organization of controls
This commit is contained in:
parent
69cb2ed84f
commit
b947d78dac
@ -4,12 +4,18 @@ use vek::*;
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Respawning;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MoveDir(pub Vec2<f32>);
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Attacking {
|
||||
pub time: f32,
|
||||
pub applied: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct OnGround;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Jumping;
|
||||
|
||||
@ -29,10 +35,18 @@ impl Attacking {
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for MoveDir {
|
||||
type Storage = VecStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Attacking {
|
||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
|
||||
}
|
||||
|
||||
impl Component for OnGround {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Jumping {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ pub use controller::Controller;
|
||||
pub use inputs::Attacking;
|
||||
pub use inputs::Gliding;
|
||||
pub use inputs::Jumping;
|
||||
pub use inputs::MoveDir;
|
||||
pub use inputs::OnGround;
|
||||
pub use inputs::Respawning;
|
||||
pub use player::Player;
|
||||
pub use stats::Dying;
|
||||
|
@ -109,6 +109,8 @@ impl State {
|
||||
ecs.register::<comp::phys::Pos>();
|
||||
ecs.register::<comp::phys::Vel>();
|
||||
ecs.register::<comp::phys::Ori>();
|
||||
ecs.register::<comp::MoveDir>();
|
||||
ecs.register::<comp::OnGround>();
|
||||
ecs.register::<comp::AnimationInfo>();
|
||||
ecs.register::<comp::Controller>();
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
use crate::{comp::Attacking, state::DeltaTime};
|
||||
use specs::{Entities, Join, Read, System, WriteStorage};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (entities, dt, mut attacks): Self::SystemData) {
|
||||
for attack in (&mut attacks).join() {
|
||||
attack.time += dt.0;
|
||||
}
|
||||
|
||||
let finished_attacks = (&entities, &mut attacks)
|
||||
.join()
|
||||
.filter(|(_, a)| a.time > 0.50) // TODO: constant
|
||||
.map(|(e, _)| e)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for entity in finished_attacks {
|
||||
attacks.remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,9 +4,8 @@ use rand::{seq::SliceRandom, thread_rng};
|
||||
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS AI agent system
|
||||
/// This system will allow NPCs to modify their controller
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
|
@ -1,15 +1,68 @@
|
||||
use crate::{comp::AnimationInfo, state::DeltaTime};
|
||||
use specs::{Join, Read, System, WriteStorage};
|
||||
use crate::{
|
||||
comp::{phys, Animation, AnimationInfo, Attacking, Gliding, Jumping, OnGround},
|
||||
state::DeltaTime,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
/// This system will apply the animation that fits best to the users actions
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (Read<'a, DeltaTime>, WriteStorage<'a, AnimationInfo>);
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, phys::Vel>,
|
||||
ReadStorage<'a, OnGround>,
|
||||
ReadStorage<'a, Jumping>,
|
||||
ReadStorage<'a, Gliding>,
|
||||
ReadStorage<'a, Attacking>,
|
||||
WriteStorage<'a, AnimationInfo>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (dt, mut animation_infos): Self::SystemData) {
|
||||
for mut animation_info in (&mut animation_infos).join() {
|
||||
fn run(
|
||||
&mut self,
|
||||
(entities, dt, velocities, on_grounds, jumpings, glidings, attackings, mut animation_infos): Self::SystemData,
|
||||
) {
|
||||
for (entity, vel, on_ground, jumping, gliding, attacking, mut animation_info) in (
|
||||
&entities,
|
||||
&velocities,
|
||||
on_grounds.maybe(),
|
||||
jumpings.maybe(),
|
||||
glidings.maybe(),
|
||||
attackings.maybe(),
|
||||
&mut animation_infos,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
animation_info.time += dt.0 as f64;
|
||||
let moving = vel.0.magnitude() > 3.0;
|
||||
|
||||
fn impossible_animation() -> Animation {
|
||||
warn!("Impossible animation");
|
||||
Animation::Idle
|
||||
}
|
||||
|
||||
let animation = match (
|
||||
on_ground.is_some(),
|
||||
moving,
|
||||
attacking.is_some(),
|
||||
gliding.is_some(),
|
||||
) {
|
||||
(true, false, false, false) => Animation::Idle,
|
||||
(true, true, false, false) => Animation::Run,
|
||||
(false, _, false, false) => Animation::Jump,
|
||||
(_, _, false, true) => Animation::Gliding,
|
||||
(_, _, true, false) => Animation::Attack,
|
||||
(_, _, true, true) => impossible_animation(),
|
||||
};
|
||||
|
||||
let last = animation_info.clone();
|
||||
let changed = last.animation != animation;
|
||||
|
||||
*animation_info = AnimationInfo {
|
||||
animation,
|
||||
time: if changed { 0.0 } else { last.time },
|
||||
changed,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
phys::{ForceUpdate, Ori, Pos, Vel},
|
||||
Animation, AnimationInfo, Attacking, Controller, Gliding, HealthSource, Jumping, Stats,
|
||||
Animation, AnimationInfo, Attacking, Controller, Gliding, HealthSource, Jumping, MoveDir,
|
||||
OnGround, Respawning, Stats,
|
||||
},
|
||||
state::{DeltaTime, Uid},
|
||||
terrain::TerrainMap,
|
||||
@ -11,16 +12,7 @@ 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 validating controller inputs
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
@ -32,8 +24,11 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, Ori>,
|
||||
WriteStorage<'a, MoveDir>,
|
||||
WriteStorage<'a, OnGround>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
WriteStorage<'a, Respawning>,
|
||||
WriteStorage<'a, Gliding>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
);
|
||||
@ -49,65 +44,64 @@ impl<'a> System<'a> for Sys {
|
||||
positions,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
mut jumps,
|
||||
mut attacks,
|
||||
mut glides,
|
||||
mut move_dirs,
|
||||
mut on_grounds,
|
||||
mut jumpings,
|
||||
mut attackings,
|
||||
mut respawns,
|
||||
mut glidings,
|
||||
mut force_updates,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (entity, controller, stats, pos, mut vel, mut ori) in (
|
||||
for (entity, controller, stats, pos, mut vel, mut ori, on_ground) in (
|
||||
&entities,
|
||||
&controllers,
|
||||
&stats,
|
||||
&positions,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
on_grounds.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
if stats.is_dead {
|
||||
// Respawn
|
||||
if controller.respawn {
|
||||
respawns.insert(entity, Respawning);
|
||||
}
|
||||
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 = controller.glide && vel.0.z < 0.0;
|
||||
let move_dir = if controller.move_dir.magnitude() > 1.0 {
|
||||
controller.move_dir.normalized()
|
||||
// Glide
|
||||
if controller.glide && on_ground.is_none() && attackings.get(entity).is_none() {
|
||||
glidings.insert(entity, Gliding);
|
||||
} else {
|
||||
controller.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 controller.jump && vel.0.z <= 0.0 {
|
||||
vel.0.z = HUMANOID_JUMP_ACCEL;
|
||||
}
|
||||
} 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;
|
||||
glidings.remove(entity);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
// Move dir
|
||||
move_dirs.insert(
|
||||
entity,
|
||||
MoveDir(if controller.move_dir.magnitude() > 1.0 {
|
||||
controller.move_dir.normalized()
|
||||
} else {
|
||||
controller.move_dir
|
||||
}),
|
||||
);
|
||||
|
||||
// Attack
|
||||
if controller.attack && attacks.get(entity).is_none() {
|
||||
attacks.insert(entity, Attacking::start());
|
||||
if controller.attack
|
||||
&& attackings.get(entity).is_none()
|
||||
&& glidings.get(entity).is_none()
|
||||
{
|
||||
attackings.insert(entity, Attacking::start());
|
||||
}
|
||||
|
||||
// Jump
|
||||
if on_grounds.get(entity).is_some() && controller.jump && vel.0.z <= 0.0 {
|
||||
jumpings.insert(entity, Jumping);
|
||||
} else {
|
||||
jumpings.remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
phys::{ForceUpdate, Ori, Pos, Vel},
|
||||
Animation, AnimationInfo, Attacking, Controller, Gliding, HealthSource, Jumping, Stats,
|
||||
Animation, AnimationInfo, Attacking, Gliding, HealthSource, Jumping, MoveDir, OnGround,
|
||||
Respawning, Stats,
|
||||
},
|
||||
state::{DeltaTime, Uid},
|
||||
terrain::TerrainMap,
|
||||
@ -11,7 +12,17 @@ use log::warn;
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS AI agent system
|
||||
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 = (
|
||||
@ -20,11 +31,13 @@ impl<'a> System<'a> for Sys {
|
||||
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>,
|
||||
ReadStorage<'a, Controller>,
|
||||
WriteStorage<'a, Respawning>,
|
||||
WriteStorage<'a, Jumping>,
|
||||
WriteStorage<'a, Gliding>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
@ -39,88 +52,99 @@ impl<'a> System<'a> for Sys {
|
||||
dt,
|
||||
terrain,
|
||||
positions,
|
||||
on_grounds,
|
||||
move_dirs,
|
||||
mut velocities,
|
||||
mut orientations,
|
||||
mut animation_infos,
|
||||
mut stats,
|
||||
controllers,
|
||||
mut jumps,
|
||||
glides,
|
||||
mut attacks,
|
||||
mut respawnings,
|
||||
mut jumpings,
|
||||
glidings,
|
||||
mut attackings,
|
||||
mut force_updates,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
for (entity, pos, controller, stats, mut ori, mut vel) in (
|
||||
// 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,
|
||||
&positions,
|
||||
&controllers,
|
||||
&stats,
|
||||
&mut orientations,
|
||||
&mut velocities,
|
||||
&mut orientations,
|
||||
on_grounds.maybe(),
|
||||
move_dirs.maybe(),
|
||||
jumpings.maybe(),
|
||||
glidings.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
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 animation = if on_ground {
|
||||
if controller.move_dir.magnitude() > 0.01 {
|
||||
Animation::Run
|
||||
} else if attacks.get(entity).is_some() {
|
||||
Animation::Attack
|
||||
} else {
|
||||
Animation::Idle
|
||||
}
|
||||
} else if controller.glide {
|
||||
Animation::Gliding
|
||||
} else {
|
||||
Animation::Jump
|
||||
};
|
||||
|
||||
let last = animation_infos
|
||||
.get_mut(entity)
|
||||
.cloned()
|
||||
.unwrap_or(AnimationInfo::default());
|
||||
let changed = last.animation != animation;
|
||||
|
||||
if let Err(err) = animation_infos.insert(
|
||||
entity,
|
||||
AnimationInfo {
|
||||
animation,
|
||||
time: if changed { 0.0 } else { last.time },
|
||||
changed,
|
||||
},
|
||||
) {
|
||||
warn!("Inserting AnimationInfo for an entity failed: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
for (entity, &uid, pos, ori, attacking) in
|
||||
(&entities, &uids, &positions, &orientations, &mut attacks).join()
|
||||
{
|
||||
if !attacking.applied {
|
||||
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);
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
attacking.applied = true;
|
||||
_ => 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub mod actions;
|
||||
pub mod agent;
|
||||
pub mod animation;
|
||||
pub mod controller;
|
||||
@ -12,17 +11,15 @@ 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";
|
||||
const INPUTS_SYS: &str = "inputs_sys";
|
||||
const ANIMATION_SYS: &str = "animation_sys";
|
||||
const STATS_SYS: &str = "stats_sys";
|
||||
|
||||
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(phys::Sys, PHYS_SYS, &[]);
|
||||
dispatch_builder.add(inputs::Sys, INPUTS_SYS, &[]);
|
||||
dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]);
|
||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[INPUTS_SYS]);
|
||||
|
@ -1,18 +1,15 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
phys::{Pos, Vel},
|
||||
Stats,
|
||||
OnGround, Stats,
|
||||
},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS physics system
|
||||
pub struct Sys;
|
||||
|
||||
const GRAVITY: f32 = 9.81 * 4.0;
|
||||
const FRIC_GROUND: f32 = 0.15;
|
||||
const FRIC_AIR: f32 = 0.015;
|
||||
@ -38,34 +35,53 @@ fn integrate_forces(dt: f32, mut lv: Vec3<f32>, damp: f32) -> Vec3<f32> {
|
||||
lv
|
||||
}
|
||||
|
||||
/// 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, Pos>,
|
||||
WriteStorage<'a, Vel>,
|
||||
WriteStorage<'a, OnGround>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (terrain, dt, stats, mut positions, mut velocities): Self::SystemData) {
|
||||
for (stats, pos, vel) in (&stats, &mut positions, &mut velocities).join() {
|
||||
fn run(
|
||||
&mut self,
|
||||
(entities, terrain, dt, stats, mut positions, mut velocities, mut on_grounds): Self::SystemData,
|
||||
) {
|
||||
for (entity, stats, pos, vel) in (&entities, &stats, &mut positions, &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;
|
||||
|
||||
// Movement
|
||||
pos.0 += vel.0 * dt.0;
|
||||
|
||||
// Update OnGround component
|
||||
if 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
|
||||
{
|
||||
on_grounds.insert(entity, OnGround);
|
||||
} else {
|
||||
on_grounds.remove(entity);
|
||||
}
|
||||
|
||||
// Integrate forces
|
||||
// Friction is assumed to be a constant dependent on location
|
||||
let friction = 50.0 * if on_ground { FRIC_GROUND } else { FRIC_AIR };
|
||||
let friction = 50.0
|
||||
* if on_grounds.get(entity).is_some() {
|
||||
FRIC_GROUND
|
||||
} else {
|
||||
FRIC_AIR
|
||||
};
|
||||
vel.0 = integrate_forces(dt.0, vel.0, friction);
|
||||
|
||||
// Basic collision with terrain
|
||||
|
@ -5,9 +5,8 @@ use crate::{
|
||||
use log::warn;
|
||||
use specs::{Entities, Join, Read, System, WriteStorage};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
/// This system kills players
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
|
Loading…
Reference in New Issue
Block a user