Commit 8838682f authored by Mckol's avatar Mckol

Added Controller support

parent 5598fe71
......@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- weapon control system
- Game pauses when in singleplayer and pause menu
- Added authentication system (to play on the official server register on https://account.veloren.net)
- Added gamepad/controller support
### Changed
......
This diff is collapsed.
......@@ -35,6 +35,9 @@ specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git" }
# Mathematics
vek = { version = "0.9.9", features = ["serde"] }
# Controller
gilrs = { version = "0.7", features = ["serde"] }
# Singleplayer
server = { package = "veloren-server", path = "../server", optional = true }
......
This diff is collapsed.
......@@ -5,6 +5,7 @@ pub struct KeyState {
pub left: bool,
pub up: bool,
pub down: bool,
pub analog_matrix: Vec2<f32>,
}
impl KeyState {
......@@ -14,16 +15,21 @@ impl KeyState {
left: false,
up: false,
down: false,
analog_matrix: Vec2::zero(),
}
}
pub fn dir_vec(&self) -> Vec2<f32> {
let dir = 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 },
);
let dir = if self.analog_matrix == Vec2::zero() {
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 },
)
} else {
self.analog_matrix
};
if dir.magnitude_squared() == 0.0 {
if dir.magnitude_squared() <= 1.0 {
dir
} else {
dir.normalized()
......
......@@ -6,6 +6,7 @@
pub mod ui;
pub mod anim;
pub mod audio;
pub mod controller;
mod ecs;
pub mod error;
pub mod hud;
......
......@@ -15,7 +15,7 @@ use crate::{
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
PostProcessPipeline, Renderer, Shadow, SkyboxLocals, SkyboxPipeline,
},
window::Event,
window::{AnalogGameInput, Event},
};
use common::{
comp,
......@@ -50,6 +50,7 @@ pub struct Scene {
lights: Consts<Light>,
shadows: Consts<Shadow>,
camera: Camera,
camera_input_state: Vec2<f32>,
skybox: Skybox,
postprocess: PostProcess,
......@@ -85,6 +86,7 @@ impl Scene {
.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT])
.unwrap(),
camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson),
camera_input_state: Vec2::zero(),
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
......@@ -146,6 +148,17 @@ impl Scene {
.zoom_switch(delta * (0.05 + self.camera.get_distance() * 0.01));
true
},
Event::AnalogGameInput(input) => match input {
AnalogGameInput::CameraX(d) => {
self.camera_input_state.x = d;
true
},
AnalogGameInput::CameraY(d) => {
self.camera_input_state.y = d;
true
},
_ => false,
},
// All other events are unhandled
_ => false,
}
......@@ -185,6 +198,12 @@ impl Scene {
_ => 1_f32,
};
// Add the analog input to camera
self.camera
.rotate_by(Vec3::from([self.camera_input_state.x, 0.0, 0.0]));
self.camera
.rotate_by(Vec3::from([0.0, self.camera_input_state.y, 0.0]));
// Alter camera position to match player.
let tilt = self.camera.get_orientation().y;
let dist = self.camera.get_distance();
......
......@@ -5,7 +5,7 @@ use crate::{
key_state::KeyState,
render::Renderer,
scene::{camera, Scene, SceneData},
window::{Event, GameInput},
window::{AnalogGameInput, Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult,
};
use client::{self, Client, Event::Chat};
......@@ -365,6 +365,17 @@ impl PlayState for SessionState {
Event::InputUpdate(GameInput::Charge, state) => {
self.inputs.charge.set_state(state);
},
Event::AnalogGameInput(input) => match input {
AnalogGameInput::MovementX(v) => {
self.key_state.analog_matrix.x = v;
},
AnalogGameInput::MovementY(v) => {
self.key_state.analog_matrix.y = v;
},
other => {
self.scene.handle_input_event(Event::AnalogGameInput(other));
},
},
// Pass all other events to the scene
event => {
......
......@@ -7,7 +7,7 @@ use crate::{
};
use directories::{ProjectDirs, UserDirs};
use glutin::{MouseButton, VirtualKeyCode};
use hashbrown::HashSet;
use hashbrown::{HashMap, HashSet};
use log::warn;
use serde_derive::{Deserialize, Serialize};
use std::{fs, io::prelude::*, path::PathBuf};
......@@ -105,6 +105,225 @@ impl Default for ControlSettings {
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct GamepadSettings {
pub game_buttons: con_settings::GameButtons,
pub menu_buttons: con_settings::MenuButtons,
pub game_axis: con_settings::GameAxis,
pub menu_axis: con_settings::MenuAxis,
pub game_analog_buttons: con_settings::GameAnalogButton,
pub menu_analog_buttons: con_settings::MenuAnalogButton,
pub pan_sensitivity: u32,
pub pan_invert_y: bool,
pub axis_deadzones: HashMap<crate::controller::Axis, f32>,
pub button_deadzones: HashMap<crate::controller::AnalogButton, f32>,
pub mouse_emulation_sensitivity: u32,
pub inverted_axes: Vec<crate::controller::Axis>,
}
impl Default for GamepadSettings {
fn default() -> Self {
Self {
game_buttons: con_settings::GameButtons::default(),
menu_buttons: con_settings::MenuButtons::default(),
game_axis: con_settings::GameAxis::default(),
menu_axis: con_settings::MenuAxis::default(),
game_analog_buttons: con_settings::GameAnalogButton::default(),
menu_analog_buttons: con_settings::MenuAnalogButton::default(),
pan_sensitivity: 10,
pan_invert_y: false,
axis_deadzones: HashMap::new(),
button_deadzones: HashMap::new(),
mouse_emulation_sensitivity: 12,
inverted_axes: Vec::new(),
}
}
}
pub mod con_settings {
use crate::controller::*;
use gilrs::{Axis as GilAxis, Button as GilButton};
use serde_derive::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct GameButtons {
pub primary: Button,
pub secondary: Button,
pub toggle_cursor: Button,
pub escape: Button,
pub enter: Button,
pub command: Button,
pub move_forward: Button,
pub move_left: Button,
pub move_back: Button,
pub move_right: Button,
pub jump: Button,
pub sit: Button,
pub glide: Button,
pub climb: Button,
pub climb_down: Button,
pub wall_leap: Button,
pub mount: Button,
pub map: Button,
pub bag: Button,
pub quest_log: Button,
pub character_window: Button,
pub social: Button,
pub spellbook: Button,
pub settings: Button,
pub help: Button,
pub toggle_interface: Button,
pub toggle_debug: Button,
pub fullscreen: Button,
pub screenshot: Button,
pub toggle_ingame_ui: Button,
pub roll: Button,
pub respawn: Button,
pub interact: Button,
pub toggle_wield: Button,
pub charge: Button,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct MenuButtons {
pub up: Button,
pub down: Button,
pub left: Button,
pub right: Button,
pub scroll_up: Button,
pub scroll_down: Button,
pub scroll_left: Button,
pub scroll_right: Button,
pub home: Button,
pub end: Button,
pub apply: Button,
pub back: Button,
pub exit: Button,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct GameAxis {
pub movement_x: Axis,
pub movement_y: Axis,
pub camera_x: Axis,
pub camera_y: Axis,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct MenuAxis {
pub move_x: Axis,
pub move_y: Axis,
pub scroll_x: Axis,
pub scroll_y: Axis,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct GameAnalogButton {}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct MenuAnalogButton {}
impl Default for GameButtons {
fn default() -> Self {
// binding to unknown = getting skipped from processing
Self {
primary: Button::Simple(GilButton::RightTrigger2),
secondary: Button::Simple(GilButton::LeftTrigger2),
toggle_cursor: Button::Simple(GilButton::Select),
escape: Button::Simple(GilButton::Mode),
enter: Button::Simple(GilButton::Unknown),
command: Button::Simple(GilButton::Unknown),
move_forward: Button::Simple(GilButton::Unknown),
move_left: Button::Simple(GilButton::Unknown),
move_back: Button::Simple(GilButton::Unknown),
move_right: Button::Simple(GilButton::Unknown),
jump: Button::Simple(GilButton::South),
sit: Button::Simple(GilButton::West),
glide: Button::Simple(GilButton::LeftTrigger),
climb: Button::Simple(GilButton::South),
climb_down: Button::Simple(GilButton::Unknown),
wall_leap: Button::Simple(GilButton::Unknown),
mount: Button::Simple(GilButton::North),
map: Button::Simple(GilButton::DPadRight),
bag: Button::Simple(GilButton::DPadDown),
quest_log: Button::Simple(GilButton::Unknown),
character_window: Button::Simple(GilButton::Unknown),
social: Button::Simple(GilButton::Unknown),
spellbook: Button::Simple(GilButton::Unknown),
settings: Button::Simple(GilButton::Unknown),
help: Button::Simple(GilButton::Unknown),
toggle_interface: Button::Simple(GilButton::Unknown),
toggle_debug: Button::Simple(GilButton::Unknown),
fullscreen: Button::Simple(GilButton::Unknown),
screenshot: Button::Simple(GilButton::DPadUp),
toggle_ingame_ui: Button::Simple(GilButton::Unknown),
roll: Button::Simple(GilButton::RightTrigger),
respawn: Button::Simple(GilButton::RightTrigger2),
interact: Button::Simple(GilButton::LeftTrigger2),
toggle_wield: Button::Simple(GilButton::DPadLeft),
charge: Button::Simple(GilButton::Unknown),
}
}
}
impl Default for MenuButtons {
fn default() -> Self {
Self {
up: Button::Simple(GilButton::Unknown),
down: Button::Simple(GilButton::Unknown),
left: Button::Simple(GilButton::Unknown),
right: Button::Simple(GilButton::Unknown),
scroll_up: Button::Simple(GilButton::Unknown),
scroll_down: Button::Simple(GilButton::Unknown),
scroll_left: Button::Simple(GilButton::Unknown),
scroll_right: Button::Simple(GilButton::Unknown),
home: Button::Simple(GilButton::DPadUp),
end: Button::Simple(GilButton::DPadDown),
apply: Button::Simple(GilButton::South),
back: Button::Simple(GilButton::East),
exit: Button::Simple(GilButton::Mode),
}
}
}
impl Default for GameAxis {
fn default() -> Self {
Self {
movement_x: Axis::Simple(GilAxis::LeftStickX),
movement_y: Axis::Simple(GilAxis::LeftStickY),
camera_x: Axis::Simple(GilAxis::RightStickX),
camera_y: Axis::Simple(GilAxis::RightStickY),
}
}
}
impl Default for MenuAxis {
fn default() -> Self {
Self {
move_x: Axis::Simple(GilAxis::RightStickX),
move_y: Axis::Simple(GilAxis::RightStickY),
scroll_x: Axis::Simple(GilAxis::LeftStickX),
scroll_y: Axis::Simple(GilAxis::LeftStickY),
}
}
}
impl Default for GameAnalogButton {
fn default() -> Self { Self {} }
}
impl Default for MenuAnalogButton {
fn default() -> Self { Self {} }
}
}
/// `GameplaySettings` contains sensitivity and gameplay options.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
......@@ -298,6 +517,7 @@ pub struct Settings {
pub logon_commands: Vec<String>,
pub language: LanguageSettings,
pub screenshots_path: PathBuf,
pub controller: GamepadSettings,
}
impl Default for Settings {
......@@ -329,6 +549,7 @@ impl Default for Settings {
logon_commands: Vec::new(),
language: LanguageSettings::default(),
screenshots_path,
controller: GamepadSettings::default(),
}
}
}
......
......@@ -634,8 +634,8 @@ impl Ui {
mesh.push_quad(create_ui_quad(
gl_aabr(rect),
Aabr {
min: Vec2::new(0.0, 0.0),
max: Vec2::new(0.0, 0.0),
min: Vec2::zero(),
max: Vec2::zero(),
},
color,
UiMode::Geometry,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment