mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'inputs-enhancements' into 'master'
Inputs enhancements See merge request veloren/veloren!671
This commit is contained in:
commit
a6ef802f9c
@ -1,8 +1,13 @@
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use sphynx::Uid;
|
||||
use std::ops::Add;
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
/// Default duration for how long before an input is considered 'held'.
|
||||
pub const DEFAULT_HOLD_DURATION: Duration = Duration::from_millis(250);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ControlEvent {
|
||||
Mount(Uid),
|
||||
@ -11,18 +16,101 @@ pub enum ControlEvent {
|
||||
//Respawn,
|
||||
}
|
||||
|
||||
/// The various states an input can be in
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum InputState {
|
||||
Pressed,
|
||||
Unpressed,
|
||||
}
|
||||
|
||||
/// Whether a key is pressed or unpressed
|
||||
/// and how long it has been in that state
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Input {
|
||||
// Should not be pub because duration should
|
||||
// always be reset when state is updated
|
||||
state: InputState,
|
||||
// Should only be updated by npc agents
|
||||
// through appropriate fn
|
||||
duration: Duration,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
/// Whether input is in `InputState::Pressed` state
|
||||
pub fn is_pressed(&self) -> bool {
|
||||
self.state == InputState::Pressed
|
||||
}
|
||||
/// Whether input has been in current state longer than
|
||||
/// `DEFAULT_HOLD_DURATION`
|
||||
pub fn is_held_down(&self) -> bool {
|
||||
(self.is_pressed() && self.duration >= DEFAULT_HOLD_DURATION)
|
||||
}
|
||||
|
||||
/// Sets the `input::state` and resets `input::duration`
|
||||
///
|
||||
///
|
||||
/// `new_state` == `true` -> `InputState::Pressed`
|
||||
///
|
||||
/// `new_state` == `false` -> `InputState::Unpressed`
|
||||
pub fn set_state(&mut self, new_state: bool) {
|
||||
// Only update if state switches
|
||||
match (new_state, self.is_pressed()) {
|
||||
(true, false) => {
|
||||
self.state = InputState::Pressed;
|
||||
self.duration = Duration::default();
|
||||
}
|
||||
(false, true) => {
|
||||
self.state = InputState::Unpressed;
|
||||
self.duration = Duration::default();
|
||||
}
|
||||
(_, _) => {}
|
||||
};
|
||||
}
|
||||
|
||||
/// Sets `input::duration`
|
||||
pub fn inc_dur(&mut self, dur: Duration) {
|
||||
self.duration = self.duration + dur;
|
||||
}
|
||||
|
||||
/// Returns `input::duration`
|
||||
pub fn get_dur(&self) -> Duration {
|
||||
self.duration
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Input {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
state: InputState::Unpressed,
|
||||
duration: Duration::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Duration> for Input {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, dur: Duration) -> Self {
|
||||
Self {
|
||||
state: self.state,
|
||||
duration: self.duration.checked_add(dur).unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ControllerInputs {
|
||||
pub primary: bool,
|
||||
pub secondary: bool,
|
||||
pub sit: bool,
|
||||
pub jump: bool,
|
||||
pub roll: bool,
|
||||
pub glide: bool,
|
||||
pub climb: bool,
|
||||
pub climb_down: bool,
|
||||
pub wall_leap: bool,
|
||||
pub respawn: bool,
|
||||
pub primary: Input,
|
||||
pub secondary: Input,
|
||||
pub sit: Input,
|
||||
pub jump: Input,
|
||||
pub roll: Input,
|
||||
pub glide: Input,
|
||||
pub climb: Input,
|
||||
pub climb_down: Input,
|
||||
pub wall_leap: Input,
|
||||
pub respawn: Input,
|
||||
pub toggle_wield: Input,
|
||||
pub move_dir: Vec2<f32>,
|
||||
pub look_dir: Vec3<f32>,
|
||||
}
|
||||
@ -34,7 +122,25 @@ pub struct Controller {
|
||||
pub events: Vec<ControlEvent>,
|
||||
}
|
||||
|
||||
impl ControllerInputs {
|
||||
/// Updates all inputs, accounting for delta time
|
||||
pub fn tick(&mut self, dt: Duration) {
|
||||
self.primary = self.primary + dt;
|
||||
self.secondary = self.secondary + dt;
|
||||
self.sit = self.sit + dt;
|
||||
self.jump = self.jump + dt;
|
||||
self.roll = self.roll + dt;
|
||||
self.glide = self.glide + dt;
|
||||
self.climb = self.climb + dt;
|
||||
self.climb_down = self.climb_down + dt;
|
||||
self.wall_leap = self.wall_leap + dt;
|
||||
self.respawn = self.respawn + dt;
|
||||
self.toggle_wield = self.toggle_wield + dt;
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
/// Sets all inputs to default
|
||||
pub fn reset(&mut self) {
|
||||
*self = Self::default();
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ pub use body::{
|
||||
};
|
||||
pub use character_state::{ActionState, CharacterState, MovementState};
|
||||
pub use controller::{
|
||||
ControlEvent, Controller, ControllerInputs, InventoryManip, MountState, Mounting,
|
||||
ControlEvent, Controller, ControllerInputs, Input, InputState, InventoryManip, MountState,
|
||||
Mounting,
|
||||
};
|
||||
pub use inputs::CanBuild;
|
||||
pub use inventory::{item, Inventory, InventoryUpdate, Item, ItemKind};
|
||||
|
@ -67,7 +67,7 @@ impl<'a> System<'a> for Sys {
|
||||
let tgt_pos = tgt_pos.0 + *offset;
|
||||
|
||||
if tgt_pos.z > pos.0.z + 1.0 {
|
||||
inputs.jump = true;
|
||||
inputs.jump.set_state(true);
|
||||
}
|
||||
|
||||
// Move towards the target.
|
||||
@ -113,19 +113,19 @@ impl<'a> System<'a> for Sys {
|
||||
// Fight (and slowly move closer)
|
||||
inputs.move_dir =
|
||||
Vec2::<f32>::from(target_pos.0 - pos.0).normalized() * 0.01;
|
||||
inputs.primary = true;
|
||||
inputs.primary.set_state(true);
|
||||
} else if dist < SIGHT_DIST {
|
||||
inputs.move_dir =
|
||||
Vec2::<f32>::from(target_pos.0 - pos.0).normalized() * 0.96;
|
||||
|
||||
if rand::random::<f32>() < 0.02 {
|
||||
inputs.roll = true;
|
||||
inputs.roll.set_state(true);
|
||||
}
|
||||
|
||||
if target_character.movement == Glide && target_pos.0.z > pos.0.z + 5.0
|
||||
{
|
||||
inputs.glide = true;
|
||||
inputs.jump = true;
|
||||
inputs.glide.set_state(true);
|
||||
inputs.jump.set_state(true);
|
||||
}
|
||||
} else {
|
||||
choose_new = true;
|
||||
|
@ -70,7 +70,7 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
if stats.is_dead {
|
||||
// Respawn
|
||||
if inputs.respawn {
|
||||
if inputs.respawn.is_pressed() {
|
||||
server_emitter.emit(ServerEvent::Respawn(entity));
|
||||
}
|
||||
continue;
|
||||
@ -97,19 +97,19 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Glide
|
||||
// TODO: Check for glide ability/item
|
||||
if inputs.glide
|
||||
if inputs.glide.is_pressed()
|
||||
&& !physics.on_ground
|
||||
&& (character.action == Idle || character.action.is_wield())
|
||||
&& character.movement == Jump
|
||||
&& body.is_humanoid()
|
||||
{
|
||||
character.movement = Glide;
|
||||
} else if !inputs.glide && character.movement == Glide {
|
||||
character.movement = Jump;
|
||||
} else if !inputs.glide.is_pressed() && character.movement == Glide {
|
||||
// character.movement = Jump;
|
||||
}
|
||||
|
||||
// Sit
|
||||
if inputs.sit
|
||||
if inputs.sit.is_pressed()
|
||||
&& physics.on_ground
|
||||
&& character.action == Idle
|
||||
&& character.movement != Sit
|
||||
@ -123,7 +123,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Wield
|
||||
if inputs.primary
|
||||
if inputs.primary.is_pressed()
|
||||
&& character.action == Idle
|
||||
&& (character.movement == Stand || character.movement == Run)
|
||||
{
|
||||
@ -138,7 +138,7 @@ impl<'a> System<'a> for Sys {
|
||||
power,
|
||||
..
|
||||
}) => {
|
||||
if inputs.primary
|
||||
if inputs.primary.is_pressed()
|
||||
&& (character.movement == Stand
|
||||
|| character.movement == Run
|
||||
|| character.movement == Jump)
|
||||
@ -177,7 +177,7 @@ impl<'a> System<'a> for Sys {
|
||||
..
|
||||
}) => {
|
||||
// Melee Attack
|
||||
if inputs.primary
|
||||
if inputs.primary.is_pressed()
|
||||
&& (character.movement == Stand
|
||||
|| character.movement == Run
|
||||
|| character.movement == Jump)
|
||||
@ -192,7 +192,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
// Magical Bolt
|
||||
if inputs.secondary
|
||||
if inputs.secondary.is_pressed()
|
||||
&& (
|
||||
character.movement == Stand
|
||||
//|| character.movement == Run
|
||||
@ -237,13 +237,13 @@ impl<'a> System<'a> for Sys {
|
||||
kind: item::Tool::Debug(item::Debug::Boost),
|
||||
..
|
||||
}) => {
|
||||
if inputs.primary {
|
||||
if inputs.primary.is_pressed() {
|
||||
local_emitter.emit(LocalEvent::Boost {
|
||||
entity,
|
||||
vel: inputs.look_dir * 7.0,
|
||||
});
|
||||
}
|
||||
if inputs.secondary {
|
||||
if inputs.secondary.is_pressed() {
|
||||
// Go upward
|
||||
local_emitter.emit(LocalEvent::Boost {
|
||||
entity,
|
||||
@ -255,7 +255,7 @@ impl<'a> System<'a> for Sys {
|
||||
kind: item::Tool::Debug(item::Debug::Possess),
|
||||
..
|
||||
}) => {
|
||||
if inputs.primary
|
||||
if inputs.primary.is_pressed()
|
||||
&& (character.movement == Stand
|
||||
|| character.movement == Run
|
||||
|| character.movement == Jump)
|
||||
@ -288,14 +288,14 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
// Block
|
||||
if inputs.secondary
|
||||
if inputs.secondary.is_pressed()
|
||||
&& (character.movement == Stand || character.movement == Run)
|
||||
&& character.action.is_wield()
|
||||
{
|
||||
character.action = Block {
|
||||
time_left: Duration::from_secs(5),
|
||||
};
|
||||
} else if !inputs.secondary && character.action.is_block() {
|
||||
} else if !inputs.secondary.is_pressed() && character.action.is_block() {
|
||||
character.action = Wield {
|
||||
time_left: Duration::default(),
|
||||
};
|
||||
@ -304,7 +304,7 @@ impl<'a> System<'a> for Sys {
|
||||
// All other tools
|
||||
Some(ItemKind::Tool { .. }) => {
|
||||
// Attack
|
||||
if inputs.primary
|
||||
if inputs.primary.is_pressed()
|
||||
&& (character.movement == Stand
|
||||
|| character.movement == Run
|
||||
|| character.movement == Jump)
|
||||
@ -320,14 +320,14 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Block
|
||||
if inputs.secondary
|
||||
if inputs.secondary.is_pressed()
|
||||
&& (character.movement == Stand || character.movement == Run)
|
||||
&& character.action.is_wield()
|
||||
{
|
||||
character.action = Block {
|
||||
time_left: Duration::from_secs(5),
|
||||
};
|
||||
} else if !inputs.secondary && character.action.is_block() {
|
||||
} else if !inputs.secondary.is_pressed() && character.action.is_block() {
|
||||
character.action = Wield {
|
||||
time_left: Duration::default(),
|
||||
};
|
||||
@ -335,7 +335,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
None => {
|
||||
// Attack
|
||||
if inputs.primary
|
||||
if inputs.primary.is_pressed()
|
||||
&& (character.movement == Stand
|
||||
|| character.movement == Run
|
||||
|| character.movement == Jump)
|
||||
@ -351,7 +351,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Roll
|
||||
if inputs.roll
|
||||
if inputs.roll.is_pressed()
|
||||
&& (character.action == Idle || character.action.is_wield())
|
||||
&& character.movement == Run
|
||||
&& physics.on_ground
|
||||
@ -362,19 +362,26 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
// Jump
|
||||
if (inputs.jump && physics.on_ground && vel.0.z <= 0.0 && !character.movement.is_roll())
|
||||
|| (inputs.jump && character.movement == Swim)
|
||||
if (inputs.jump.is_pressed() && !inputs.jump.is_held_down())
|
||||
&& physics.on_ground
|
||||
&& vel.0.z <= 0.0
|
||||
&& !character.movement.is_roll()
|
||||
|| (inputs.jump.is_pressed() && character.movement == Swim)
|
||||
{
|
||||
local_emitter.emit(LocalEvent::Jump(entity));
|
||||
}
|
||||
|
||||
// Wall leap
|
||||
if inputs.wall_leap {
|
||||
if inputs.wall_leap.is_pressed() {
|
||||
if let (Some(_wall_dir), Climb) = (physics.on_wall, character.movement) {
|
||||
//local_emitter.emit(LocalEvent::WallLeap { entity, wall_dir });
|
||||
}
|
||||
}
|
||||
|
||||
if let (true, Wield { .. }) = (inputs.toggle_wield.is_pressed(), character.action) {
|
||||
character.action = Idle;
|
||||
}
|
||||
|
||||
// Process controller events
|
||||
for event in controller.events.drain(..) {
|
||||
match event {
|
||||
|
@ -197,12 +197,13 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Climb
|
||||
if let (true, Some(_wall_dir)) = (
|
||||
(inputs.climb | inputs.climb_down) && vel.0.z <= CLIMB_SPEED,
|
||||
(inputs.climb.is_pressed() | inputs.climb_down.is_pressed())
|
||||
&& vel.0.z <= CLIMB_SPEED,
|
||||
physics.on_wall,
|
||||
) {
|
||||
if inputs.climb_down && !inputs.climb {
|
||||
if inputs.climb_down.is_pressed() && !inputs.climb.is_pressed() {
|
||||
vel.0 -= dt.0 * vel.0.map(|e| e.abs().powf(1.5) * e.signum() * 6.0);
|
||||
} else if inputs.climb && !inputs.climb_down {
|
||||
} else if inputs.climb.is_pressed() && !inputs.climb_down.is_pressed() {
|
||||
vel.0.z = (vel.0.z + dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED);
|
||||
} else {
|
||||
vel.0.z = vel.0.z + dt.0 * GRAVITY * 1.5;
|
||||
|
@ -54,6 +54,7 @@ impl SessionState {
|
||||
impl SessionState {
|
||||
/// Tick the session (and the client attached to it).
|
||||
fn tick(&mut self, dt: Duration) -> Result<(), Error> {
|
||||
self.inputs.tick(dt);
|
||||
for event in self.client.borrow_mut().tick(self.inputs.clone(), dt)? {
|
||||
match event {
|
||||
Chat {
|
||||
@ -177,12 +178,12 @@ impl PlayState for SessionState {
|
||||
client.place_block(build_pos, self.selected_block);
|
||||
}
|
||||
} else {
|
||||
self.inputs.primary = state
|
||||
self.inputs.primary.set_state(state);
|
||||
}
|
||||
}
|
||||
|
||||
Event::InputUpdate(GameInput::Secondary, state) => {
|
||||
self.inputs.secondary = false; // To be changed later on
|
||||
self.inputs.secondary.set_state(false); // To be changed later on
|
||||
|
||||
let mut client = self.client.borrow_mut();
|
||||
|
||||
@ -203,7 +204,7 @@ impl PlayState for SessionState {
|
||||
.map(|cs| cs.action.is_wield())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
self.inputs.secondary = state;
|
||||
self.inputs.secondary.set_state(state);
|
||||
} else {
|
||||
if let Some(select_pos) = select_pos {
|
||||
client.collect_block(select_pos);
|
||||
@ -226,30 +227,34 @@ impl PlayState for SessionState {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.inputs.roll = state;
|
||||
self.inputs.roll.set_state(state);
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::Respawn, state) => {
|
||||
self.inputs.respawn = state;
|
||||
self.inputs.respawn.set_state(state);
|
||||
}
|
||||
Event::InputUpdate(GameInput::Jump, state) => {
|
||||
self.inputs.jump = state;
|
||||
self.inputs.jump.set_state(state);
|
||||
}
|
||||
Event::InputUpdate(GameInput::Sit, state) => {
|
||||
self.inputs.sit = state;
|
||||
self.inputs.sit.set_state(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.inputs.glide = state;
|
||||
self.inputs.glide.set_state(state);
|
||||
}
|
||||
Event::InputUpdate(GameInput::Climb, state) => {
|
||||
self.inputs.climb.set_state(state)
|
||||
}
|
||||
Event::InputUpdate(GameInput::Climb, state) => self.inputs.climb = state,
|
||||
Event::InputUpdate(GameInput::ClimbDown, state) => {
|
||||
self.inputs.climb_down = state
|
||||
self.inputs.climb_down.set_state(state)
|
||||
}
|
||||
Event::InputUpdate(GameInput::WallLeap, state) => {
|
||||
self.inputs.wall_leap.set_state(state)
|
||||
}
|
||||
Event::InputUpdate(GameInput::WallLeap, state) => self.inputs.wall_leap = state,
|
||||
Event::InputUpdate(GameInput::Mount, true) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
if client.is_mounted() {
|
||||
@ -315,6 +320,9 @@ impl PlayState for SessionState {
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::InputUpdate(GameInput::ToggleWield, state) => {
|
||||
self.inputs.toggle_wield.set_state(state)
|
||||
}
|
||||
|
||||
// Pass all other events to the scene
|
||||
event => {
|
||||
|
@ -47,6 +47,7 @@ pub struct ControlSettings {
|
||||
pub roll: KeyMouse,
|
||||
pub respawn: KeyMouse,
|
||||
pub interact: KeyMouse,
|
||||
pub toggle_wield: KeyMouse,
|
||||
}
|
||||
|
||||
impl Default for ControlSettings {
|
||||
@ -85,6 +86,7 @@ impl Default for ControlSettings {
|
||||
roll: KeyMouse::Mouse(MouseButton::Middle),
|
||||
respawn: KeyMouse::Mouse(MouseButton::Left),
|
||||
interact: KeyMouse::Key(VirtualKeyCode::E),
|
||||
toggle_wield: KeyMouse::Key(VirtualKeyCode::T),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ pub enum GameInput {
|
||||
Roll,
|
||||
Respawn,
|
||||
Interact,
|
||||
ToggleWield,
|
||||
}
|
||||
|
||||
/// Represents an incoming event from the window.
|
||||
@ -221,6 +222,9 @@ impl Window {
|
||||
map.entry(settings.controls.interact)
|
||||
.or_default()
|
||||
.push(GameInput::Interact);
|
||||
map.entry(settings.controls.toggle_wield)
|
||||
.or_default()
|
||||
.push(GameInput::ToggleWield);
|
||||
|
||||
let keypress_map = HashMap::new();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user