mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
add player movement with basic physics ecs system
Former-commit-id: f2e151971a42b25bfd1971311f5a06535a577007
This commit is contained in:
parent
993ee68037
commit
6f5f80f749
@ -7,10 +7,7 @@ use vek::*;
|
|||||||
use threadpool;
|
use threadpool;
|
||||||
|
|
||||||
// Project
|
// Project
|
||||||
use common::{
|
use common::{comp::phys::Vel, state::State, terrain::TerrainChunk};
|
||||||
state::State,
|
|
||||||
terrain::TerrainChunk,
|
|
||||||
};
|
|
||||||
use world::World;
|
use world::World;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -21,6 +18,7 @@ pub enum Error {
|
|||||||
|
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
// TODO: Use this type to manage client input
|
// TODO: Use this type to manage client input
|
||||||
|
pub move_vec: Vec2<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
@ -61,6 +59,7 @@ impl Client {
|
|||||||
// TODO: Get rid of this
|
// TODO: Get rid of this
|
||||||
pub fn with_test_state(mut self) -> Self {
|
pub fn with_test_state(mut self) -> Self {
|
||||||
self.chunk = Some(self.world.generate_chunk(Vec3::zero()));
|
self.chunk = Some(self.world.generate_chunk(Vec3::zero()));
|
||||||
|
self.player = Some(self.state.new_test_player());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +75,11 @@ impl Client {
|
|||||||
/// Get a mutable reference to the client's game state.
|
/// Get a mutable reference to the client's game state.
|
||||||
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
||||||
|
|
||||||
|
/// Get the player entity
|
||||||
|
pub fn player(&self) -> Option<EcsEntity> {
|
||||||
|
self.player
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current tick number.
|
/// Get the current tick number.
|
||||||
pub fn get_tick(&self) -> u64 {
|
pub fn get_tick(&self) -> u64 {
|
||||||
self.tick
|
self.tick
|
||||||
@ -95,6 +99,27 @@ impl Client {
|
|||||||
// 4) Go through the terrain update queue and apply all changes to the terrain
|
// 4) Go through the terrain update queue and apply all changes to the terrain
|
||||||
// 5) Finish the tick, passing control of the main thread back to the frontend
|
// 5) Finish the tick, passing control of the main thread back to the frontend
|
||||||
|
|
||||||
|
// (step 1)
|
||||||
|
if let Some(p) = self.player {
|
||||||
|
let vel = input.move_vec;
|
||||||
|
|
||||||
|
const MIN_LOOKING: f32 = 0.5;
|
||||||
|
const LEANING_FAC: f32 = 0.05;
|
||||||
|
|
||||||
|
let dir = Vec3::from([
|
||||||
|
// Rotation
|
||||||
|
match vel.magnitude() > MIN_LOOKING {
|
||||||
|
true => vel[0].atan2(vel[1]),
|
||||||
|
_ => 0.0,
|
||||||
|
},
|
||||||
|
// Lean
|
||||||
|
Vec2::new(vel[0], vel[1]).magnitude() * LEANING_FAC,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// TODO: Set acceleration instead and adjust dir calculations accordingly
|
||||||
|
self.state.write_component(p, Vel(Vec3::from(vel)));
|
||||||
|
}
|
||||||
|
|
||||||
// Tick the client's LocalState (step 3)
|
// Tick the client's LocalState (step 3)
|
||||||
self.state.tick(dt);
|
self.state.tick(dt);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ pub mod clock;
|
|||||||
pub mod comp;
|
pub mod comp;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
pub mod sys;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod volumes;
|
pub mod volumes;
|
||||||
|
@ -2,15 +2,12 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
use specs::World as EcsWorld;
|
|
||||||
use shred::{Fetch, FetchMut};
|
use shred::{Fetch, FetchMut};
|
||||||
|
use specs::{Builder, Component, DispatcherBuilder, Entity as EcsEntity, World as EcsWorld};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{comp, sys, terrain::TerrainMap};
|
||||||
comp,
|
|
||||||
terrain::TerrainMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// How much faster should an in-game day be compared to a real day?
|
/// How much faster should an in-game day be compared to a real day?
|
||||||
// TODO: Don't hard-code this
|
// TODO: Don't hard-code this
|
||||||
@ -22,6 +19,10 @@ struct TimeOfDay(f64);
|
|||||||
/// A resource to store the tick (i.e: physics) time
|
/// A resource to store the tick (i.e: physics) time
|
||||||
struct Time(f64);
|
struct Time(f64);
|
||||||
|
|
||||||
|
/// A resource used to store the time since the last tick
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DeltaTime(pub f64);
|
||||||
|
|
||||||
pub struct Changes {
|
pub struct Changes {
|
||||||
pub new_chunks: Vec<Vec3<i32>>,
|
pub new_chunks: Vec<Vec3<i32>>,
|
||||||
pub changed_chunks: Vec<Vec3<i32>>,
|
pub changed_chunks: Vec<Vec3<i32>>,
|
||||||
@ -59,6 +60,7 @@ impl State {
|
|||||||
// Register resources used by the ECS
|
// Register resources used by the ECS
|
||||||
ecs_world.add_resource(TimeOfDay(0.0));
|
ecs_world.add_resource(TimeOfDay(0.0));
|
||||||
ecs_world.add_resource(Time(0.0));
|
ecs_world.add_resource(Time(0.0));
|
||||||
|
ecs_world.add_resource(DeltaTime(0.0));
|
||||||
ecs_world.add_resource(TerrainMap::new());
|
ecs_world.add_resource(TerrainMap::new());
|
||||||
|
|
||||||
// Register common components with the state
|
// Register common components with the state
|
||||||
@ -70,15 +72,36 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Get rid of this
|
||||||
|
pub fn new_test_player(&mut self) -> EcsEntity {
|
||||||
|
self.ecs_world
|
||||||
|
.create_entity()
|
||||||
|
.with(comp::phys::Pos(Vec3::default()))
|
||||||
|
.with(comp::phys::Vel(Vec3::default()))
|
||||||
|
.with(comp::phys::Dir(Vec3::default()))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a component
|
||||||
|
pub fn write_component<C: Component>(&mut self, e: EcsEntity, c: C) {
|
||||||
|
let _ = self.ecs_world.write_storage().insert(e, c);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the internal ECS world
|
/// Get a reference to the internal ECS world
|
||||||
pub fn ecs_world(&self) -> &EcsWorld { &self.ecs_world }
|
pub fn ecs_world(&self) -> &EcsWorld {
|
||||||
|
&self.ecs_world
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the `Changes` structure of the state. This contains
|
/// Get a reference to the `Changes` structure of the state. This contains
|
||||||
/// information about state that has changed since the last game tick.
|
/// information about state that has changed since the last game tick.
|
||||||
pub fn changes(&self) -> &Changes { &self.changes }
|
pub fn changes(&self) -> &Changes {
|
||||||
|
&self.changes
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get rid of this since it shouldn't be needed
|
// TODO: Get rid of this since it shouldn't be needed
|
||||||
pub fn changes_mut(&mut self) -> &mut Changes { &mut self.changes }
|
pub fn changes_mut(&mut self) -> &mut Changes {
|
||||||
|
&mut self.changes
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current in-game time of day.
|
/// Get the current in-game time of day.
|
||||||
///
|
///
|
||||||
@ -95,12 +118,12 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to this state's terrain.
|
/// Get a reference to this state's terrain.
|
||||||
pub fn terrain<'a>(&'a self) -> Fetch<'a, TerrainMap> {
|
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
||||||
self.ecs_world.read_resource::<TerrainMap>()
|
self.ecs_world.read_resource::<TerrainMap>()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Get rid of this since it shouldn't be needed
|
// TODO: Get rid of this since it shouldn't be needed
|
||||||
pub fn terrain_mut<'a>(&'a mut self) -> FetchMut<'a, TerrainMap> {
|
pub fn terrain_mut(&mut self) -> FetchMut<TerrainMap> {
|
||||||
self.ecs_world.write_resource::<TerrainMap>()
|
self.ecs_world.write_resource::<TerrainMap>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +132,17 @@ impl State {
|
|||||||
// Change the time accordingly
|
// Change the time accordingly
|
||||||
self.ecs_world.write_resource::<TimeOfDay>().0 += dt.as_float_secs() * DAY_CYCLE_FACTOR;
|
self.ecs_world.write_resource::<TimeOfDay>().0 += dt.as_float_secs() * DAY_CYCLE_FACTOR;
|
||||||
self.ecs_world.write_resource::<Time>().0 += dt.as_float_secs();
|
self.ecs_world.write_resource::<Time>().0 += dt.as_float_secs();
|
||||||
|
|
||||||
|
// Run systems to update the world
|
||||||
|
self.ecs_world.write_resource::<DeltaTime>().0 = dt.as_float_secs();
|
||||||
|
|
||||||
|
// Create and run dispatcher for ecs systems
|
||||||
|
let mut dispatch_builder = DispatcherBuilder::new();
|
||||||
|
sys::add_local_systems(&mut dispatch_builder);
|
||||||
|
// This dispatches all the systems in parallel
|
||||||
|
dispatch_builder.build().dispatch(&self.ecs_world.res);
|
||||||
|
|
||||||
|
self.ecs_world.maintain();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up the state after a tick
|
/// Clean up the state after a tick
|
||||||
|
11
common/src/sys/mod.rs
Normal file
11
common/src/sys/mod.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
pub mod phys;
|
||||||
|
|
||||||
|
// External
|
||||||
|
use specs::DispatcherBuilder;
|
||||||
|
|
||||||
|
// System names
|
||||||
|
const MOVEMENT_SYS: &str = "movement_sys";
|
||||||
|
|
||||||
|
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||||
|
dispatch_builder.add(phys::MovementSys, MOVEMENT_SYS, &[]);
|
||||||
|
}
|
25
common/src/sys/phys.rs
Normal file
25
common/src/sys/phys.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Library
|
||||||
|
use specs::{Join, Read, ReadStorage, System, WriteStorage};
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::{
|
||||||
|
comp::phys::{Pos, Vel},
|
||||||
|
state::DeltaTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic ECS physics system
|
||||||
|
pub struct MovementSys;
|
||||||
|
|
||||||
|
impl<'a> System<'a> for MovementSys {
|
||||||
|
type SystemData = (
|
||||||
|
WriteStorage<'a, Pos>,
|
||||||
|
ReadStorage<'a, Vel>,
|
||||||
|
Read<'a, DeltaTime>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn run(&mut self, (mut positions, velocities, dt): Self::SystemData) {
|
||||||
|
(&mut positions, &velocities)
|
||||||
|
.join() // this can be parallelized with par_join()
|
||||||
|
.for_each(|(pos, vel)| pos.0 += vel.0 * dt.0 as f32 * 100.0);
|
||||||
|
}
|
||||||
|
}
|
32
voxygen/src/key_state.rs
Normal file
32
voxygen/src/key_state.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use vek::Vec2;
|
||||||
|
|
||||||
|
pub struct KeyState {
|
||||||
|
pub right: bool,
|
||||||
|
pub left: bool,
|
||||||
|
pub up: bool,
|
||||||
|
pub down: bool,
|
||||||
|
pub jump: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyState {
|
||||||
|
pub fn new() -> KeyState {
|
||||||
|
KeyState {
|
||||||
|
right: false,
|
||||||
|
left: false,
|
||||||
|
up: false,
|
||||||
|
down: false,
|
||||||
|
jump: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dir_vec(&self) -> Vec2<f32> {
|
||||||
|
Vec2::<f32>::new(
|
||||||
|
if self.right { 1.0 } else { 0.0 } + if self.left { -1.0 } else { 0.0 },
|
||||||
|
if self.up { 1.0 } else { 0.0 } + if self.down { -1.0 } else { 0.0 },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jump(&self) -> bool {
|
||||||
|
self.jump
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
pub mod anim;
|
pub mod anim;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod key_state;
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
@ -67,11 +67,14 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Locals {
|
impl Locals {
|
||||||
pub fn default() -> Self {
|
pub fn new(model_mat: Mat4<f32>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
model_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
model_mat: arr_to_mat(model_mat.into_col_array()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self::new(Mat4::identity())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoneData {
|
impl BoneData {
|
||||||
@ -82,9 +85,7 @@ impl BoneData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
Self {
|
Self::new(Mat4::identity())
|
||||||
bone_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ impl Camera {
|
|||||||
/// Rotate the camera about its focus by the given delta, limiting the input accordingly.
|
/// Rotate the camera about its focus by the given delta, limiting the input accordingly.
|
||||||
pub fn rotate_by(&mut self, delta: Vec3<f32>) {
|
pub fn rotate_by(&mut self, delta: Vec3<f32>) {
|
||||||
self.ori += delta;
|
self.ori += delta;
|
||||||
|
// Wrap camera roll
|
||||||
|
self.ori.x = self.ori.x % (2.0 * PI);
|
||||||
// Clamp camera pitch to the vertical limits
|
// Clamp camera pitch to the vertical limits
|
||||||
self.ori.y = self.ori.y
|
self.ori.y = self.ori.y
|
||||||
.min(PI / 2.0)
|
.min(PI / 2.0)
|
||||||
@ -75,4 +77,7 @@ impl Camera {
|
|||||||
pub fn get_aspect_ratio(&self) -> f32 { self.aspect }
|
pub fn get_aspect_ratio(&self) -> f32 { self.aspect }
|
||||||
/// Set the aspect ratio of the camera.
|
/// Set the aspect ratio of the camera.
|
||||||
pub fn set_aspect_ratio(&mut self, aspect: f32) { self.aspect = aspect; }
|
pub fn set_aspect_ratio(&mut self, aspect: f32) { self.aspect = aspect; }
|
||||||
|
|
||||||
|
/// Get the orientation of the camera
|
||||||
|
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ use vek::*;
|
|||||||
use dot_vox;
|
use dot_vox;
|
||||||
|
|
||||||
// Project
|
// Project
|
||||||
use common::figure::Segment;
|
|
||||||
use client::Client;
|
use client::Client;
|
||||||
|
use common::{comp::phys::Pos as PosComp, figure::Segment};
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -138,6 +138,22 @@ impl Scene {
|
|||||||
|
|
||||||
/// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
|
/// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
|
||||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
|
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
|
||||||
|
// Get player position
|
||||||
|
let player_pos = match client.player() {
|
||||||
|
Some(entity) => {
|
||||||
|
client
|
||||||
|
.state()
|
||||||
|
.ecs_world()
|
||||||
|
.read_storage::<PosComp>()
|
||||||
|
.get(entity)
|
||||||
|
.expect("There was no position component on the player entity!")
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
None => Vec3::default(),
|
||||||
|
};
|
||||||
|
// Alter camera position to match player
|
||||||
|
self.camera.set_focus_pos(player_pos);
|
||||||
|
|
||||||
// Compute camera matrices
|
// Compute camera matrices
|
||||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
||||||
|
|
||||||
@ -161,7 +177,15 @@ impl Scene {
|
|||||||
&mut self.test_figure.skeleton,
|
&mut self.test_figure.skeleton,
|
||||||
client.state().get_time(),
|
client.state().get_time(),
|
||||||
);
|
);
|
||||||
self.test_figure.update_locals(renderer, FigureLocals::default()).unwrap();
|
|
||||||
|
// Calculate entity model matrix
|
||||||
|
let model_mat = Mat4::<f32>::translation_3d(player_pos);
|
||||||
|
//* Mat4::rotation_z(PI - entity.look_dir().x)
|
||||||
|
//* Mat4::rotation_x(entity.look_dir().y);
|
||||||
|
|
||||||
|
self.test_figure
|
||||||
|
.update_locals(renderer, FigureLocals::new(model_mat))
|
||||||
|
.unwrap();
|
||||||
self.test_figure.update_skeleton(renderer).unwrap();
|
self.test_figure.update_skeleton(renderer).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use crate::{
|
|||||||
PlayState,
|
PlayState,
|
||||||
PlayStateResult,
|
PlayStateResult,
|
||||||
GlobalState,
|
GlobalState,
|
||||||
|
key_state::KeyState,
|
||||||
window::{Event, Key},
|
window::{Event, Key},
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
scene::Scene,
|
scene::Scene,
|
||||||
@ -27,6 +28,7 @@ const FPS: u64 = 60;
|
|||||||
pub struct SessionState {
|
pub struct SessionState {
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
client: Client,
|
client: Client,
|
||||||
|
key_state: KeyState,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an active game session (i.e: one that is being played)
|
/// Represents an active game session (i.e: one that is being played)
|
||||||
@ -38,6 +40,7 @@ impl SessionState {
|
|||||||
// Create a scene for this session. The scene handles visible elements of the game world
|
// Create a scene for this session. The scene handles visible elements of the game world
|
||||||
scene: Scene::new(renderer, &client),
|
scene: Scene::new(renderer, &client),
|
||||||
client,
|
client,
|
||||||
|
key_state: KeyState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,7 +51,16 @@ const BG_COLOR: Rgba<f32> = Rgba { r: 0.0, g: 0.3, b: 1.0, a: 1.0 };
|
|||||||
impl SessionState {
|
impl SessionState {
|
||||||
/// Tick the session (and the client attached to it)
|
/// Tick the session (and the client attached to it)
|
||||||
pub fn tick(&mut self, dt: Duration) -> Result<(), Error> {
|
pub fn tick(&mut self, dt: Duration) -> Result<(), Error> {
|
||||||
self.client.tick(client::Input {}, dt)?;
|
// 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_vec = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
||||||
|
|
||||||
|
self.client.tick(client::Input { move_vec }, dt)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +113,16 @@ impl PlayState for SessionState {
|
|||||||
Event::KeyDown(Key::ToggleCursor) => {
|
Event::KeyDown(Key::ToggleCursor) => {
|
||||||
global_state.window.grab_cursor(!global_state.window.is_cursor_grabbed());
|
global_state.window.grab_cursor(!global_state.window.is_cursor_grabbed());
|
||||||
},
|
},
|
||||||
|
// Movement Key Pressed
|
||||||
|
Event::KeyDown(Key::MoveForward) => self.key_state.up = true,
|
||||||
|
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,
|
||||||
|
// 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,
|
||||||
// Pass all other events to the scene
|
// Pass all other events to the scene
|
||||||
event => { self.scene.handle_input_event(event); },
|
event => { self.scene.handle_input_event(event); },
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
use glutin;
|
use glutin;
|
||||||
use gfx_window_glutin;
|
use gfx_window_glutin;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -18,6 +19,7 @@ pub struct Window {
|
|||||||
renderer: Renderer,
|
renderer: Renderer,
|
||||||
window: glutin::GlWindow,
|
window: glutin::GlWindow,
|
||||||
cursor_grabbed: bool,
|
cursor_grabbed: bool,
|
||||||
|
key_map: HashMap<glutin::VirtualKeyCode, Key>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -46,6 +48,13 @@ impl Window {
|
|||||||
&events_loop,
|
&events_loop,
|
||||||
).map_err(|err| Error::BackendError(Box::new(err)))?;
|
).map_err(|err| Error::BackendError(Box::new(err)))?;
|
||||||
|
|
||||||
|
let mut key_map = HashMap::new();
|
||||||
|
key_map.insert(glutin::VirtualKeyCode::Escape, Key::ToggleCursor);
|
||||||
|
key_map.insert(glutin::VirtualKeyCode::W, Key::MoveForward);
|
||||||
|
key_map.insert(glutin::VirtualKeyCode::A, Key::MoveLeft);
|
||||||
|
key_map.insert(glutin::VirtualKeyCode::S, Key::MoveBack);
|
||||||
|
key_map.insert(glutin::VirtualKeyCode::D, Key::MoveRight);
|
||||||
|
|
||||||
let tmp = Ok(Self {
|
let tmp = Ok(Self {
|
||||||
events_loop,
|
events_loop,
|
||||||
renderer: Renderer::new(
|
renderer: Renderer::new(
|
||||||
@ -56,6 +65,7 @@ impl Window {
|
|||||||
)?,
|
)?,
|
||||||
window,
|
window,
|
||||||
cursor_grabbed: false,
|
cursor_grabbed: false,
|
||||||
|
key_map,
|
||||||
});
|
});
|
||||||
tmp
|
tmp
|
||||||
}
|
}
|
||||||
@ -69,6 +79,7 @@ impl Window {
|
|||||||
let cursor_grabbed = self.cursor_grabbed;
|
let cursor_grabbed = self.cursor_grabbed;
|
||||||
let renderer = &mut self.renderer;
|
let renderer = &mut self.renderer;
|
||||||
let window = &mut self.window;
|
let window = &mut self.window;
|
||||||
|
let key_map = &self.key_map;
|
||||||
|
|
||||||
let mut events = vec![];
|
let mut events = vec![];
|
||||||
self.events_loop.poll_events(|event| match event {
|
self.events_loop.poll_events(|event| match event {
|
||||||
@ -85,11 +96,13 @@ impl Window {
|
|||||||
},
|
},
|
||||||
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),
|
||||||
glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode {
|
glutin::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode {
|
||||||
Some(glutin::VirtualKeyCode::Escape) => events.push(if input.state == glutin::ElementState::Pressed {
|
Some(keycode) => match key_map.get(&keycode) {
|
||||||
Event::KeyDown(Key::ToggleCursor)
|
Some(&key) => events.push(match input.state {
|
||||||
} else {
|
glutin::ElementState::Pressed => Event::KeyDown(key),
|
||||||
Event::KeyUp(Key::ToggleCursor)
|
_ => Event::KeyUp(key),
|
||||||
}),
|
}),
|
||||||
|
_ => {},
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
@ -126,8 +139,13 @@ impl Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a key that the game recognises after keyboard mapping
|
/// Represents a key that the game recognises after keyboard mapping
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
ToggleCursor,
|
ToggleCursor,
|
||||||
|
MoveForward,
|
||||||
|
MoveBack,
|
||||||
|
MoveLeft,
|
||||||
|
MoveRight,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an incoming event from the window
|
/// Represents an incoming event from the window
|
||||||
|
Loading…
Reference in New Issue
Block a user