diff --git a/client/src/input.rs b/client/src/input.rs index c30a12bbb9..840ee46525 100644 --- a/client/src/input.rs +++ b/client/src/input.rs @@ -1,14 +1,21 @@ use vek::*; +pub enum InputEvent { + Jump, +} + pub struct Input { - // TODO: Use this type to manage client input pub move_dir: Vec2, + pub jumping: bool, + pub events: Vec, } impl Default for Input { fn default() -> Self { Input { move_dir: Vec2::zero(), + jumping: false, + events: Vec::new(), } } } diff --git a/client/src/lib.rs b/client/src/lib.rs index 800807bade..6619facfeb 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -4,7 +4,7 @@ pub mod error; pub mod input; // Reexports -pub use crate::{error::Error, input::Input}; +pub use crate::{error::Error, input::{Input, InputEvent}}; pub use specs::join::Join; pub use specs::Entity as EcsEntity; @@ -152,6 +152,7 @@ impl Client { self.entity, comp::Control { move_dir: input.move_dir, + jumping: input.jumping, }, ); diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs index 4617e78f3c..1c299b8ba3 100644 --- a/common/src/comp/agent.rs +++ b/common/src/comp/agent.rs @@ -13,12 +13,14 @@ impl Component for Agent { #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct Control { pub move_dir: Vec2, + pub jumping: bool, } impl Default for Control { fn default() -> Self { Self { move_dir: Vec2::zero(), + jumping: false, } } } diff --git a/common/src/comp/character.rs b/common/src/comp/character.rs index 3ea3f58b64..a9e145bc45 100644 --- a/common/src/comp/character.rs +++ b/common/src/comp/character.rs @@ -119,6 +119,7 @@ pub struct AnimationHistory { pub enum Animation { Idle, Run, + Jump, } impl Component for Character { diff --git a/common/src/sys/control.rs b/common/src/sys/control.rs index 805336b939..78fd2d2866 100644 --- a/common/src/sys/control.rs +++ b/common/src/sys/control.rs @@ -1,11 +1,15 @@ // Library -use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; +use specs::{Entities, Join, Read, ReadStorage, ReadExpect, System, WriteStorage}; use vek::*; // Crate -use crate::comp::{ - phys::{Dir, Pos, Vel}, - Animation, AnimationHistory, Control, +use crate::{ + comp::{ + phys::{Dir, Pos, Vel}, + Animation, AnimationHistory, Control, + }, + terrain::TerrainMap, + vol::{ReadVol, Vox}, }; // Basic ECS AI agent system @@ -13,26 +17,47 @@ pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( + ReadExpect<'a, TerrainMap>, Entities<'a>, + ReadStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Dir>, WriteStorage<'a, AnimationHistory>, ReadStorage<'a, Control>, ); - fn run(&mut self, (entities, mut vels, mut dirs, mut anims, controls): Self::SystemData) { - for (entity, mut vel, mut dir, control) in - (&entities, &mut vels, &mut dirs, &controls).join() + fn run(&mut self, (terrain, entities, pos, mut vels, mut dirs, mut anims, controls): Self::SystemData) { + for (entity, pos, mut vel, mut dir, control) in + (&entities, &pos, &mut vels, &mut dirs, &controls).join() { - // TODO: Don't hard-code this - // Apply physics to the player: acceleration and non-linear decceleration - vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03; + 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 control.move_dir.magnitude() > 0.01 { - dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0); - Animation::Run + if on_ground { + // TODO: Don't hard-code this + // Apply physics to the player: acceleration and non-linear decceleration + vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03; + + if control.jumping { + vel.0.z += 16.0; + } } else { - Animation::Idle + // TODO: Don't hard-code this + // Apply physics to the player: acceleration and non-linear decceleration + vel.0 += control.move_dir * 0.2; + } + + let animation = if on_ground { + if control.move_dir.magnitude() > 0.01 { + dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0); + Animation::Run + } else { + Animation::Idle + } + } else { + Animation::Jump }; let last_animation = anims.get_mut(entity).map(|h| h.current); diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index b876f9b6d1..377b7c59b9 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -10,7 +10,7 @@ use vek::*; // Basic ECS physics system pub struct Sys; -const GRAVITY: f32 = 9.81 * 2.0; +const GRAVITY: f32 = 9.81 * 4.0; impl<'a> System<'a> for Sys { type SystemData = ( diff --git a/voxygen/src/key_state.rs b/voxygen/src/key_state.rs index c25bb4dd7b..3e97fe7d4a 100644 --- a/voxygen/src/key_state.rs +++ b/voxygen/src/key_state.rs @@ -25,8 +25,4 @@ impl KeyState { if self.up { 1.0 } else { 0.0 } + if self.down { -1.0 } else { 0.0 }, ) } - - pub fn jump(&self) -> bool { - self.jump - } } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index af37bb5388..a2d6cbb7aa 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -208,10 +208,15 @@ impl FigureCache { let target_skeleton = match animation_history.current { comp::character::Animation::Idle => { IdleAnimation::update_skeleton(&mut state.skeleton, time) - } + }, comp::character::Animation::Run => { RunAnimation::update_skeleton(&mut state.skeleton, time) - } + }, + comp::character::Animation::Jump => { + // TODO + // JumpAnimation::update_skeleton(&mut state.skeleton, time) + state.skeleton.clone() + }, }; state.skeleton.interpolate(&target_skeleton); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index d1b9de0361..9a93f05c91 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -1,3 +1,17 @@ +use std::{ + cell::RefCell, + rc::Rc, + time::Duration, + mem, +}; +use vek::*; +use common::clock::Clock; +use client::{ + self, + Client, + Input, + InputEvent, +}; use crate::{ hud::{Event as HudEvent, Hud}, key_state::KeyState, @@ -7,10 +21,6 @@ use crate::{ window::{Event, Key, Window}, Direction, Error, GlobalState, PlayState, PlayStateResult, }; -use client::{self, Client}; -use common::clock::Clock; -use std::{cell::RefCell, rc::Rc, time::Duration}; -use vek::*; const FPS: u64 = 60; @@ -18,6 +28,7 @@ pub struct SessionState { scene: Scene, client: Rc>, key_state: KeyState, + input_events: Vec, hud: Hud, } @@ -32,6 +43,7 @@ impl SessionState { client, key_state: KeyState::new(), hud: Hud::new(window, settings), + input_events: Vec::new(), } } } @@ -56,10 +68,18 @@ impl SessionState { let dir_vec = self.key_state.dir_vec(); let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1]; + // Take the input events + let mut input_events = Vec::new(); + mem::swap(&mut self.input_events, &mut input_events); + for event in self .client .borrow_mut() - .tick(client::Input { move_dir }, dt)? + .tick(Input { + move_dir, + jumping: self.key_state.jump, + events: input_events, + }, dt)? { match event { client::Event::Chat(msg) => { @@ -132,11 +152,16 @@ impl PlayState for SessionState { Event::KeyDown(Key::MoveBack) => self.key_state.down = true, Event::KeyDown(Key::MoveLeft) => self.key_state.left = true, Event::KeyDown(Key::MoveRight) => self.key_state.right = true, + Event::KeyDown(Key::Jump) => { + self.input_events.push(InputEvent::Jump); + self.key_state.jump = true; + }, // Movement Key Released Event::KeyUp(Key::MoveForward) => self.key_state.up = false, Event::KeyUp(Key::MoveBack) => self.key_state.down = false, Event::KeyUp(Key::MoveLeft) => self.key_state.left = false, Event::KeyUp(Key::MoveRight) => self.key_state.right = false, + Event::KeyUp(Key::Jump) => self.key_state.jump = false, // Pass all other events to the scene event => { self.scene.handle_input_event(event);