mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Prevent GameInputs from being bound to multiple keys unless explicitly allowed. Add a Reset to Defaults button for controls.
This commit is contained in:
parent
930e0028bc
commit
8e523364ac
@ -303,6 +303,8 @@ magically infused items?"#,
|
|||||||
"hud.settings.audio_device": "Audio Device",
|
"hud.settings.audio_device": "Audio Device",
|
||||||
|
|
||||||
"hud.settings.awaitingkey": "Press a key...",
|
"hud.settings.awaitingkey": "Press a key...",
|
||||||
|
"hud.settings.unbound": "None",
|
||||||
|
"hud.settings.reset_keybinds": "Reset to Defaults",
|
||||||
|
|
||||||
"hud.social": "Social",
|
"hud.social": "Social",
|
||||||
"hud.social.online": "Online",
|
"hud.social.online": "Online",
|
||||||
|
@ -67,6 +67,7 @@ const TEXT_BG: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
|
|||||||
const MENU_BG: Color = Color::Rgba(0.0, 0.0, 0.0, 0.4);
|
const MENU_BG: Color = Color::Rgba(0.0, 0.0, 0.0, 0.4);
|
||||||
//const TEXT_COLOR_2: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
|
//const TEXT_COLOR_2: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
|
||||||
const TEXT_COLOR_3: Color = Color::Rgba(1.0, 1.0, 1.0, 0.1);
|
const TEXT_COLOR_3: Color = Color::Rgba(1.0, 1.0, 1.0, 0.1);
|
||||||
|
const TEXT_BIND_CONFLICT_COLOR: Color = Color::Rgba(1.0, 0.0, 0.0, 1.0);
|
||||||
const BLACK: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
|
const BLACK: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
|
||||||
//const BG_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 0.8);
|
//const BG_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 0.8);
|
||||||
const HP_COLOR: Color = Color::Rgba(0.33, 0.63, 0.0, 1.0);
|
const HP_COLOR: Color = Color::Rgba(0.33, 0.63, 0.0, 1.0);
|
||||||
@ -282,6 +283,7 @@ pub enum Event {
|
|||||||
Quit,
|
Quit,
|
||||||
ChangeLanguage(LanguageMetadata),
|
ChangeLanguage(LanguageMetadata),
|
||||||
ChangeBinding(GameInput),
|
ChangeBinding(GameInput),
|
||||||
|
ResetBindings,
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
ChangeFreeLookBehavior(PressBehavior),
|
||||||
ChangeAutoWalkBehavior(PressBehavior),
|
ChangeAutoWalkBehavior(PressBehavior),
|
||||||
ChangeStopAutoWalkOnInput(bool),
|
ChangeStopAutoWalkOnInput(bool),
|
||||||
@ -1744,6 +1746,9 @@ impl Hud {
|
|||||||
settings_window::Event::ChangeBinding(game_input) => {
|
settings_window::Event::ChangeBinding(game_input) => {
|
||||||
events.push(Event::ChangeBinding(game_input));
|
events.push(Event::ChangeBinding(game_input));
|
||||||
},
|
},
|
||||||
|
settings_window::Event::ResetBindings => {
|
||||||
|
events.push(Event::ResetBindings);
|
||||||
|
},
|
||||||
settings_window::Event::ChangeFreeLookBehavior(behavior) => {
|
settings_window::Event::ChangeFreeLookBehavior(behavior) => {
|
||||||
events.push(Event::ChangeFreeLookBehavior(behavior));
|
events.push(Event::ChangeFreeLookBehavior(behavior));
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
img_ids::Imgs, BarNumbers, CrosshairType, PressBehavior, ShortcutNumbers, Show, XpBar, MENU_BG,
|
img_ids::Imgs, BarNumbers, CrosshairType, PressBehavior, ShortcutNumbers, Show, XpBar,
|
||||||
TEXT_COLOR,
|
ERROR_COLOR, MENU_BG, TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
||||||
@ -32,6 +32,7 @@ widget_ids! {
|
|||||||
settings_scrollbar,
|
settings_scrollbar,
|
||||||
controls_texts[],
|
controls_texts[],
|
||||||
controls_buttons[],
|
controls_buttons[],
|
||||||
|
reset_controls_button,
|
||||||
controls_alignment_rectangle,
|
controls_alignment_rectangle,
|
||||||
button_help,
|
button_help,
|
||||||
button_help2,
|
button_help2,
|
||||||
@ -250,6 +251,7 @@ pub enum Event {
|
|||||||
SpeechBubbleIcon(bool),
|
SpeechBubbleIcon(bool),
|
||||||
ChangeLanguage(LanguageMetadata),
|
ChangeLanguage(LanguageMetadata),
|
||||||
ChangeBinding(GameInput),
|
ChangeBinding(GameInput),
|
||||||
|
ResetBindings,
|
||||||
ChangeFreeLookBehavior(PressBehavior),
|
ChangeFreeLookBehavior(PressBehavior),
|
||||||
ChangeAutoWalkBehavior(PressBehavior),
|
ChangeAutoWalkBehavior(PressBehavior),
|
||||||
ChangeStopAutoWalkOnInput(bool),
|
ChangeStopAutoWalkOnInput(bool),
|
||||||
@ -1512,23 +1514,25 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
|
|
||||||
// Contents
|
// Contents
|
||||||
if let SettingsTab::Controls = self.show.settings_tab {
|
if let SettingsTab::Controls = self.show.settings_tab {
|
||||||
|
// Used for sequential placement in a flow-down pattern
|
||||||
|
let mut previous_element_id = None;
|
||||||
|
let mut keybindings_vec: Vec<GameInput> = GameInput::iterator().collect();
|
||||||
|
keybindings_vec.sort();
|
||||||
|
|
||||||
let controls = &self.global_state.settings.controls;
|
let controls = &self.global_state.settings.controls;
|
||||||
if controls.keybindings.len() > state.ids.controls_texts.len()
|
if keybindings_vec.len() > state.ids.controls_texts.len()
|
||||||
|| controls.keybindings.len() > state.ids.controls_buttons.len()
|
|| keybindings_vec.len() > state.ids.controls_buttons.len()
|
||||||
{
|
{
|
||||||
state.update(|s| {
|
state.update(|s| {
|
||||||
s.ids
|
s.ids
|
||||||
.controls_texts
|
.controls_texts
|
||||||
.resize(controls.keybindings.len(), &mut ui.widget_id_generator());
|
.resize(keybindings_vec.len(), &mut ui.widget_id_generator());
|
||||||
s.ids
|
s.ids
|
||||||
.controls_buttons
|
.controls_buttons
|
||||||
.resize(controls.keybindings.len(), &mut ui.widget_id_generator());
|
.resize(keybindings_vec.len(), &mut ui.widget_id_generator());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Used for sequential placement in a flow-down pattern
|
|
||||||
let mut previous_text_id = None;
|
|
||||||
let mut keybindings_vec: Vec<&GameInput> = controls.keybindings.keys().collect();
|
|
||||||
keybindings_vec.sort();
|
|
||||||
// Loop all existing keybindings and the ids for text and button widgets
|
// Loop all existing keybindings and the ids for text and button widgets
|
||||||
for (game_input, (&text_id, &button_id)) in keybindings_vec.into_iter().zip(
|
for (game_input, (&text_id, &button_id)) in keybindings_vec.into_iter().zip(
|
||||||
state
|
state
|
||||||
@ -1537,28 +1541,37 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.iter()
|
.iter()
|
||||||
.zip(state.ids.controls_buttons.iter()),
|
.zip(state.ids.controls_buttons.iter()),
|
||||||
) {
|
) {
|
||||||
if let Some(key) = controls.get_binding(*game_input) {
|
let (key_string, key_color) =
|
||||||
|
if self.global_state.window.remapping_keybindings == Some(game_input) {
|
||||||
|
(
|
||||||
|
String::from(self.localized_strings.get("hud.settings.awaitingkey")),
|
||||||
|
TEXT_COLOR,
|
||||||
|
)
|
||||||
|
} else if let Some(key) = controls.get_binding(game_input) {
|
||||||
|
(
|
||||||
|
key.to_string(),
|
||||||
|
if controls.has_conflicting_bindings(key) {
|
||||||
|
TEXT_BIND_CONFLICT_COLOR
|
||||||
|
} else {
|
||||||
|
TEXT_COLOR
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
String::from(self.localized_strings.get("hud.settings.unbound")),
|
||||||
|
ERROR_COLOR,
|
||||||
|
)
|
||||||
|
};
|
||||||
let loc_key = self
|
let loc_key = self
|
||||||
.localized_strings
|
.localized_strings
|
||||||
.get(game_input.get_localization_key());
|
.get(game_input.get_localization_key());
|
||||||
let key_string = match self.global_state.window.remapping_keybindings {
|
|
||||||
Some(game_input_binding) => {
|
|
||||||
if *game_input == game_input_binding {
|
|
||||||
String::from(self.localized_strings.get("hud.settings.awaitingkey"))
|
|
||||||
} else {
|
|
||||||
key.to_string()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => key.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let text_widget = Text::new(loc_key)
|
let text_widget = Text::new(loc_key)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.font_size(self.fonts.cyri.scale(18));
|
.font_size(self.fonts.cyri.scale(18));
|
||||||
let button_widget = Button::new()
|
let button_widget = Button::new()
|
||||||
.label(&key_string)
|
.label(&key_string)
|
||||||
.label_color(TEXT_COLOR)
|
.label_color(key_color)
|
||||||
.label_font_id(self.fonts.cyri.conrod_id)
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
.label_font_size(self.fonts.cyri.scale(15))
|
.label_font_size(self.fonts.cyri.scale(15))
|
||||||
.w(150.0)
|
.w(150.0)
|
||||||
@ -1566,12 +1579,10 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.border_rgba(0.0, 0.0, 0.0, 255.0)
|
.border_rgba(0.0, 0.0, 0.0, 255.0)
|
||||||
.label_y(Relative::Scalar(3.0));
|
.label_y(Relative::Scalar(3.0));
|
||||||
// Place top-left if it's the first text, else under the previous one
|
// Place top-left if it's the first text, else under the previous one
|
||||||
let text_widget = match previous_text_id {
|
let text_widget = match previous_element_id {
|
||||||
None => text_widget.top_left_with_margins_on(
|
None => {
|
||||||
state.ids.settings_content,
|
text_widget.top_left_with_margins_on(state.ids.settings_content, 10.0, 5.0)
|
||||||
10.0,
|
},
|
||||||
5.0,
|
|
||||||
),
|
|
||||||
Some(prev_id) => text_widget.down_from(prev_id, 10.0),
|
Some(prev_id) => text_widget.down_from(prev_id, 10.0),
|
||||||
};
|
};
|
||||||
let text_width = text_widget.get_w(ui).unwrap_or(0.0);
|
let text_width = text_widget.get_w(ui).unwrap_or(0.0);
|
||||||
@ -1581,14 +1592,31 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.set(button_id, ui)
|
.set(button_id, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
events.push(Event::ChangeBinding(*game_input));
|
events.push(Event::ChangeBinding(game_input));
|
||||||
}
|
}
|
||||||
// Set the previous id to the current one for the next cycle
|
// Set the previous id to the current one for the next cycle
|
||||||
previous_text_id = Some(text_id);
|
previous_element_id = Some(text_id);
|
||||||
}
|
}
|
||||||
|
if let Some(prev_id) = previous_element_id {
|
||||||
|
let key_string = self.localized_strings.get("hud.settings.reset_keybinds");
|
||||||
|
let button_widget = Button::new()
|
||||||
|
.label(&key_string)
|
||||||
|
.label_color(TEXT_COLOR)
|
||||||
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
|
.label_font_size(self.fonts.cyri.scale(18))
|
||||||
|
.down_from(prev_id, 20.0)
|
||||||
|
.w(200.0)
|
||||||
|
.rgba(0.0, 0.0, 0.0, 0.0)
|
||||||
|
.border_rgba(0.0, 0.0, 0.0, 255.0)
|
||||||
|
.label_y(Relative::Scalar(3.0))
|
||||||
|
.set(state.ids.reset_controls_button, ui);
|
||||||
|
if button_widget.was_clicked() {
|
||||||
|
events.push(Event::ResetBindings);
|
||||||
|
}
|
||||||
|
previous_element_id = Some(state.ids.reset_controls_button)
|
||||||
}
|
}
|
||||||
// Add an empty text widget to simulate some bottom margin, because conrod sucks
|
// Add an empty text widget to simulate some bottom margin, because conrod sucks
|
||||||
if let Some(prev_id) = previous_text_id {
|
if let Some(prev_id) = previous_element_id {
|
||||||
Rectangle::fill_with([1.0, 1.0], color::TRANSPARENT)
|
Rectangle::fill_with([1.0, 1.0], color::TRANSPARENT)
|
||||||
.down_from(prev_id, 10.0)
|
.down_from(prev_id, 10.0)
|
||||||
.set(state.ids.controls_alignment_rectangle, ui);
|
.set(state.ids.controls_alignment_rectangle, ui);
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
key_state::KeyState,
|
key_state::KeyState,
|
||||||
menu::char_selection::CharSelectionState,
|
menu::char_selection::CharSelectionState,
|
||||||
scene::{camera, Scene, SceneData},
|
scene::{camera, Scene, SceneData},
|
||||||
settings::AudioOutput,
|
settings::{AudioOutput, ControlSettings},
|
||||||
window::{AnalogGameInput, Event, GameInput},
|
window::{AnalogGameInput, Event, GameInput},
|
||||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||||
};
|
};
|
||||||
@ -922,6 +922,10 @@ impl PlayState for SessionState {
|
|||||||
HudEvent::ChangeBinding(game_input) => {
|
HudEvent::ChangeBinding(game_input) => {
|
||||||
global_state.window.set_keybinding_mode(game_input);
|
global_state.window.set_keybinding_mode(game_input);
|
||||||
},
|
},
|
||||||
|
HudEvent::ResetBindings => {
|
||||||
|
global_state.settings.controls = ControlSettings::default();
|
||||||
|
global_state.settings.save_to_file_warn();
|
||||||
|
},
|
||||||
HudEvent::ChangeFreeLookBehavior(behavior) => {
|
HudEvent::ChangeFreeLookBehavior(behavior) => {
|
||||||
global_state.settings.gameplay.free_look_behavior = behavior;
|
global_state.settings.gameplay.free_look_behavior = behavior;
|
||||||
},
|
},
|
||||||
|
@ -100,9 +100,23 @@ impl ControlSettings {
|
|||||||
self.keybindings.insert(game_input, key_mouse);
|
self.keybindings.insert(game_input, key_mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if this key is used for multiple GameInputs that aren't
|
||||||
|
/// expected to be safe to have bound to the same key at the same time
|
||||||
|
pub fn has_conflicting_bindings(&self, key_mouse: KeyMouse) -> bool {
|
||||||
|
if let Some(game_inputs) = self.inverse_keybindings.get(&key_mouse) {
|
||||||
|
for a in game_inputs.iter() {
|
||||||
|
for b in game_inputs.iter() {
|
||||||
|
if !GameInput::can_share_bindings(*a, *b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
pub fn default_binding(game_input: GameInput) -> KeyMouse {
|
||||||
// If a new GameInput is added, be sure to update ControlSettings::default()
|
// If a new GameInput is added, be sure to update GameInput::iterator() too!
|
||||||
// too!
|
|
||||||
match game_input {
|
match game_input {
|
||||||
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
GameInput::Primary => KeyMouse::Mouse(MouseButton::Left),
|
||||||
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
GameInput::Secondary => KeyMouse::Mouse(MouseButton::Right),
|
||||||
@ -157,68 +171,14 @@ impl ControlSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ControlSettings {
|
impl Default for ControlSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut new_settings = Self {
|
let mut new_settings = Self {
|
||||||
keybindings: HashMap::new(),
|
keybindings: HashMap::new(),
|
||||||
inverse_keybindings: HashMap::new(),
|
inverse_keybindings: HashMap::new(),
|
||||||
};
|
};
|
||||||
// Sets the initial keybindings for those GameInputs. If a new one is created in
|
for game_input in GameInput::iterator() {
|
||||||
// future, you'll have to update default_binding, and you should update this vec
|
|
||||||
// too.
|
|
||||||
let game_inputs = vec![
|
|
||||||
GameInput::Primary,
|
|
||||||
GameInput::Secondary,
|
|
||||||
GameInput::ToggleCursor,
|
|
||||||
GameInput::MoveForward,
|
|
||||||
GameInput::MoveBack,
|
|
||||||
GameInput::MoveLeft,
|
|
||||||
GameInput::MoveRight,
|
|
||||||
GameInput::Jump,
|
|
||||||
GameInput::Sit,
|
|
||||||
GameInput::Dance,
|
|
||||||
GameInput::Glide,
|
|
||||||
GameInput::Climb,
|
|
||||||
GameInput::ClimbDown,
|
|
||||||
GameInput::Swim,
|
|
||||||
//GameInput::WallLeap,
|
|
||||||
GameInput::ToggleLantern,
|
|
||||||
GameInput::Mount,
|
|
||||||
GameInput::Enter,
|
|
||||||
GameInput::Command,
|
|
||||||
GameInput::Escape,
|
|
||||||
GameInput::Map,
|
|
||||||
GameInput::Bag,
|
|
||||||
GameInput::Social,
|
|
||||||
GameInput::Spellbook,
|
|
||||||
GameInput::Settings,
|
|
||||||
GameInput::ToggleInterface,
|
|
||||||
GameInput::Help,
|
|
||||||
GameInput::ToggleDebug,
|
|
||||||
GameInput::Fullscreen,
|
|
||||||
GameInput::Screenshot,
|
|
||||||
GameInput::ToggleIngameUi,
|
|
||||||
GameInput::Roll,
|
|
||||||
GameInput::Respawn,
|
|
||||||
GameInput::Interact,
|
|
||||||
GameInput::ToggleWield,
|
|
||||||
//GameInput::Charge,
|
|
||||||
GameInput::FreeLook,
|
|
||||||
GameInput::AutoWalk,
|
|
||||||
GameInput::CycleCamera,
|
|
||||||
GameInput::Slot1,
|
|
||||||
GameInput::Slot2,
|
|
||||||
GameInput::Slot3,
|
|
||||||
GameInput::Slot4,
|
|
||||||
GameInput::Slot5,
|
|
||||||
GameInput::Slot6,
|
|
||||||
GameInput::Slot7,
|
|
||||||
GameInput::Slot8,
|
|
||||||
GameInput::Slot9,
|
|
||||||
GameInput::Slot10,
|
|
||||||
GameInput::SwapLoadout,
|
|
||||||
];
|
|
||||||
for game_input in game_inputs {
|
|
||||||
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
new_settings.insert_binding(game_input, ControlSettings::default_binding(game_input));
|
||||||
}
|
}
|
||||||
new_settings
|
new_settings
|
||||||
|
@ -123,6 +123,85 @@ impl GameInput {
|
|||||||
GameInput::SwapLoadout => "gameinput.swaploadout",
|
GameInput::SwapLoadout => "gameinput.swaploadout",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iterator() -> impl Iterator<Item = GameInput> {
|
||||||
|
[
|
||||||
|
GameInput::Primary,
|
||||||
|
GameInput::Secondary,
|
||||||
|
GameInput::ToggleCursor,
|
||||||
|
GameInput::MoveForward,
|
||||||
|
GameInput::MoveLeft,
|
||||||
|
GameInput::MoveRight,
|
||||||
|
GameInput::MoveBack,
|
||||||
|
GameInput::Jump,
|
||||||
|
GameInput::Sit,
|
||||||
|
GameInput::Dance,
|
||||||
|
GameInput::Glide,
|
||||||
|
GameInput::Climb,
|
||||||
|
GameInput::ClimbDown,
|
||||||
|
GameInput::Swim,
|
||||||
|
GameInput::ToggleLantern,
|
||||||
|
GameInput::Mount,
|
||||||
|
GameInput::Enter,
|
||||||
|
GameInput::Command,
|
||||||
|
GameInput::Escape,
|
||||||
|
GameInput::Map,
|
||||||
|
GameInput::Bag,
|
||||||
|
GameInput::Social,
|
||||||
|
GameInput::Spellbook,
|
||||||
|
GameInput::Settings,
|
||||||
|
GameInput::ToggleInterface,
|
||||||
|
GameInput::Help,
|
||||||
|
GameInput::ToggleDebug,
|
||||||
|
GameInput::Fullscreen,
|
||||||
|
GameInput::Screenshot,
|
||||||
|
GameInput::ToggleIngameUi,
|
||||||
|
GameInput::Roll,
|
||||||
|
GameInput::Respawn,
|
||||||
|
GameInput::Interact,
|
||||||
|
GameInput::ToggleWield,
|
||||||
|
GameInput::FreeLook,
|
||||||
|
GameInput::AutoWalk,
|
||||||
|
GameInput::Slot1,
|
||||||
|
GameInput::Slot2,
|
||||||
|
GameInput::Slot3,
|
||||||
|
GameInput::Slot4,
|
||||||
|
GameInput::Slot5,
|
||||||
|
GameInput::Slot6,
|
||||||
|
GameInput::Slot7,
|
||||||
|
GameInput::Slot8,
|
||||||
|
GameInput::Slot9,
|
||||||
|
GameInput::Slot10,
|
||||||
|
GameInput::SwapLoadout,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if `a` and `b` are able to be bound to the same key at the
|
||||||
|
/// same time without conflict. For example, the player can't jump and climb
|
||||||
|
/// at the same time, so these can be bound to the same key.
|
||||||
|
pub fn can_share_bindings(a: GameInput, b: GameInput) -> bool {
|
||||||
|
a.get_representative_binding() == b.get_representative_binding()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If two GameInputs are able to be bound at the same time, then they will
|
||||||
|
/// return the same value from this function (the representative value for
|
||||||
|
/// that set). This models the Find operation of a disjoint-set data
|
||||||
|
/// structure.
|
||||||
|
fn get_representative_binding(&self) -> GameInput {
|
||||||
|
match self {
|
||||||
|
GameInput::Jump => GameInput::Jump,
|
||||||
|
GameInput::Climb => GameInput::Jump,
|
||||||
|
GameInput::Swim => GameInput::Jump,
|
||||||
|
GameInput::Respawn => GameInput::Jump,
|
||||||
|
|
||||||
|
GameInput::FreeLook => GameInput::FreeLook,
|
||||||
|
GameInput::AutoWalk => GameInput::FreeLook,
|
||||||
|
|
||||||
|
_ => *self,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a key that the game menus recognise after input mapping
|
/// Represents a key that the game menus recognise after input mapping
|
||||||
|
Loading…
Reference in New Issue
Block a user