add gamecontrollerdb, update default inputs, add reset controls option

This commit is contained in:
Sallai József 2022-08-01 03:18:43 +03:00
parent f74ec19cb5
commit 4cfbcc50ac
11 changed files with 1877 additions and 22 deletions

File diff suppressed because it is too large Load Diff

View File

@ -160,7 +160,10 @@
"rebind_confirm_menu": {
"title": "Press button for \"{control}\"",
"cancel": "(Esc to cancel)"
}
},
"reset_confirm": "Reset...",
"reset_confirm_menu_title": "Reset controls?"
}
},

View File

@ -152,7 +152,10 @@
"rebind_confirm_menu": {
"title": "新しい「ジャンプ」ボタンを押す",
"cancel": "(Escキーを押してキャンセル)"
}
},
"reset_confirm": "リセット",
"reset_confirm_menu_title": "ボタンをリセットしますか?"
}
},

View File

@ -101,6 +101,7 @@ impl BuiltinFS {
FSNode::File("builtin_font.fnt", include_bytes!("builtin/builtin_font.fnt")),
FSNode::File("builtin_font_0.png", include_bytes!("builtin/builtin_font_0.png")),
FSNode::File("builtin_font_1.png", include_bytes!("builtin/builtin_font_1.png")),
FSNode::File("gamecontrollerdb.txt", include_bytes!("builtin/gamecontrollerdb.txt")),
FSNode::File(
"organya-wavetable-doukutsu.bin",
include_bytes!("builtin/organya-wavetable-doukutsu.bin"),

View File

@ -1,12 +1,12 @@
use std::any::Any;
use imgui::DrawData;
use std::any::Any;
use crate::common::{Color, Rect};
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::graphics::BlendMode;
use crate::Game;
use crate::graphics::VSyncMode;
use crate::Game;
#[repr(C)]
#[derive(Copy, Clone)]
@ -25,7 +25,7 @@ pub enum BackendShader {
}
pub trait Backend {
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>>;
fn create_event_loop(&self, ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>>;
}
pub trait BackendEventLoop {
@ -41,7 +41,9 @@ pub trait BackendRenderer {
fn present(&mut self) -> GameResult;
fn set_vsync_mode(&mut self, _mode: VSyncMode) -> GameResult { Ok(()) }
fn set_vsync_mode(&mut self, _mode: VSyncMode) -> GameResult {
Ok(())
}
fn prepare_draw(&mut self, _width: f32, _height: f32) -> GameResult {
Ok(())

View File

@ -4,13 +4,12 @@ use std::mem;
use std::rc::Rc;
use std::sync::Arc;
use glutin::{Api, ContextBuilder, GlProfile, GlRequest, PossiblyCurrent, WindowedContext};
use glutin::event::{ElementState, Event, TouchPhase, VirtualKeyCode, WindowEvent};
use glutin::event_loop::{ControlFlow, EventLoop};
use glutin::window::WindowBuilder;
use glutin::{Api, ContextBuilder, GlProfile, GlRequest, PossiblyCurrent, WindowedContext};
use imgui::{DrawCmdParams, DrawData, DrawIdx, DrawVert};
use crate::{Game, GAME_SUSPENDED};
use crate::common::Rect;
use crate::framework::backend::{Backend, BackendEventLoop, BackendRenderer, BackendTexture, SpriteBatchCommand};
use crate::framework::context::Context;
@ -19,6 +18,7 @@ use crate::framework::gl;
use crate::framework::keyboard::ScanCode;
use crate::framework::render_opengl::{GLContext, OpenGLRenderer};
use crate::input::touch_controls::TouchPoint;
use crate::{Game, GAME_SUSPENDED};
pub struct GlutinBackend;
@ -29,7 +29,7 @@ impl GlutinBackend {
}
impl Backend for GlutinBackend {
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>> {
fn create_event_loop(&self, _ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
#[cfg(target_os = "android")]
loop {
match ndk_glue::native_window().as_ref() {
@ -60,7 +60,8 @@ impl GlutinEventLoop {
#[cfg(target_os = "android")]
let windowed_context = windowed_context.with_gl(GlRequest::Specific(Api::OpenGlEs, (2, 0)));
let windowed_context = windowed_context.with_gl_profile(GlProfile::Core)
let windowed_context = windowed_context
.with_gl_profile(GlProfile::Core)
.with_gl_debug_flag(false)
.with_pixel_format(24, 8)
.with_vsync(true);
@ -338,7 +339,7 @@ impl BackendEventLoop for GlutinEventLoop {
std::ptr::null()
}
};
*user_data = Rc::into_raw(refs) as *mut c_void;
result

View File

@ -22,7 +22,7 @@ impl NullBackend {
}
impl Backend for NullBackend {
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>> {
fn create_event_loop(&self, _ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
Ok(Box::new(NullEventLoop))
}
}

View File

@ -37,6 +37,8 @@ use crate::Game;
use crate::GameError::RenderError;
use crate::GAME_SUSPENDED;
use super::filesystem;
pub struct SDL2Backend {
context: Sdl,
size_hint: (u16, u16),
@ -55,8 +57,8 @@ impl SDL2Backend {
}
impl Backend for SDL2Backend {
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>> {
SDL2EventLoop::new(&self.context, self.size_hint)
fn create_event_loop(&self, ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
SDL2EventLoop::new(&self.context, self.size_hint, ctx)
}
}
@ -149,10 +151,13 @@ struct SDL2Context {
}
impl SDL2EventLoop {
pub fn new(sdl: &Sdl, size_hint: (u16, u16)) -> GameResult<Box<dyn BackendEventLoop>> {
pub fn new(sdl: &Sdl, size_hint: (u16, u16), ctx: &Context) -> GameResult<Box<dyn BackendEventLoop>> {
let event_pump = sdl.event_pump().map_err(GameError::WindowError)?;
let video = sdl.video().map_err(GameError::WindowError)?;
let game_controller = sdl.game_controller().map_err(GameError::GamepadError)?;
let mut controller_mappings = filesystem::open(ctx, "/builtin/gamecontrollerdb.txt")?;
game_controller.load_mappings_from_read(&mut controller_mappings).unwrap();
let gl_attr = video.gl_attr();

View File

@ -37,7 +37,7 @@ impl Context {
pub fn run(&mut self, game: &mut Game) -> GameResult {
let backend = init_backend(self.headless, self.size_hint)?;
let mut event_loop = backend.create_event_loop()?;
let mut event_loop = backend.create_event_loop(self)?;
self.renderer = Some(event_loop.new_renderer(self as *mut Context)?);
event_loop.run(game, self);

View File

@ -5,7 +5,10 @@ use crate::framework::error::GameResult;
use crate::framework::gamepad::{self, Axis, AxisDirection, Button, PlayerControllerInputType};
use crate::framework::keyboard::ScanCode;
use crate::input::combined_menu_controller::CombinedMenuController;
use crate::settings::{ControllerType, PlayerControllerButtonMap, PlayerKeyMap};
use crate::settings::{
p1_default_keymap, p2_default_keymap, player_default_controller_button_map, ControllerType,
PlayerControllerButtonMap, PlayerKeyMap,
};
use crate::shared_game_state::SharedGameState;
use super::{ControlMenuData, Menu, MenuEntry, MenuSelectionResult};
@ -31,6 +34,7 @@ enum CurrentMenu {
ControllerMenu,
RebindMenu,
ConfirmRebindMenu,
ConfirmResetMenu,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
@ -50,6 +54,7 @@ impl Default for ControllerMenuEntry {
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum RebindMenuEntry {
Control(ControlEntry),
Reset,
Back,
}
@ -59,6 +64,19 @@ impl Default for RebindMenuEntry {
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum ConfirmResetMenuEntry {
Title,
Yes,
No,
}
impl Default for ConfirmResetMenuEntry {
fn default() -> Self {
ConfirmResetMenuEntry::No
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum Player {
Player1,
@ -118,6 +136,7 @@ pub struct ControlsMenu {
controller: Menu<ControllerMenuEntry>,
rebind: Menu<RebindMenuEntry>,
confirm_rebind: Menu<usize>,
confirm_reset: Menu<ConfirmResetMenuEntry>,
selected_player: Player,
selected_controller: ControllerType,
@ -136,12 +155,14 @@ impl ControlsMenu {
let controller = Menu::new(0, 0, 220, 0);
let rebind = Menu::new(0, 0, 220, 0);
let confirm_rebind = Menu::new(0, 0, 220, 0);
let confirm_reset = Menu::new(0, 0, 160, 0);
ControlsMenu {
current: CurrentMenu::ControllerMenu,
controller,
rebind,
confirm_rebind,
confirm_reset,
selected_player: Player::Player1,
selected_controller: ControllerType::Keyboard,
@ -174,6 +195,13 @@ impl ControlsMenu {
.push_entry(ControllerMenuEntry::Rebind, MenuEntry::Active(state.t("menus.controls_menu.rebind")));
self.controller.push_entry(ControllerMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
self.confirm_reset.push_entry(
ConfirmResetMenuEntry::Title,
MenuEntry::Disabled(state.t("menus.controls_menu.reset_confirm_menu_title")),
);
self.confirm_reset.push_entry(ConfirmResetMenuEntry::Yes, MenuEntry::Active(state.t("common.yes")));
self.confirm_reset.push_entry(ConfirmResetMenuEntry::No, MenuEntry::Active(state.t("common.no")));
self.player1_key_map = self.init_key_map(&state.settings.player1_key_map);
self.player2_key_map = self.init_key_map(&state.settings.player2_key_map);
self.player1_controller_button_map =
@ -206,6 +234,11 @@ impl ControlsMenu {
self.confirm_rebind.update_height();
self.confirm_rebind.x = ((state.canvas_size.0 - self.confirm_rebind.width as f32) / 2.0).floor() as isize;
self.confirm_rebind.y = ((state.canvas_size.1 - self.confirm_rebind.height as f32) / 2.0).floor() as isize;
self.confirm_reset.update_width(state);
self.confirm_reset.update_height();
self.confirm_reset.x = ((state.canvas_size.0 - self.confirm_reset.width as f32) / 2.0).floor() as isize;
self.confirm_reset.y = ((state.canvas_size.1 - self.confirm_reset.height as f32) / 2.0).floor() as isize;
}
fn init_key_map(&self, settings_key_map: &PlayerKeyMap) -> Vec<(ControlEntry, ScanCode)> {
@ -319,6 +352,7 @@ impl ControlsMenu {
}
}
self.rebind.push_entry(RebindMenuEntry::Reset, MenuEntry::Active(state.t("menus.controls_menu.reset_confirm")));
self.rebind.push_entry(RebindMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
}
@ -395,6 +429,33 @@ impl ControlsMenu {
}
}
fn reset_controls(&mut self, state: &mut SharedGameState, ctx: &Context) -> GameResult {
match self.selected_player {
Player::Player1 => {
if self.selected_controller == ControllerType::Keyboard {
state.settings.player1_key_map = p1_default_keymap();
self.player1_key_map = self.init_key_map(&state.settings.player1_key_map);
} else {
state.settings.player1_controller_button_map = player_default_controller_button_map();
self.player1_controller_button_map =
self.init_controller_button_map(&state.settings.player1_controller_button_map);
}
}
Player::Player2 => {
if self.selected_controller == ControllerType::Keyboard {
state.settings.player2_key_map = p2_default_keymap();
self.player2_key_map = self.init_key_map(&state.settings.player2_key_map);
} else {
state.settings.player2_controller_button_map = player_default_controller_button_map();
self.player2_controller_button_map =
self.init_controller_button_map(&state.settings.player2_controller_button_map);
}
}
}
state.settings.save(ctx)
}
fn is_key_occupied(&self, scan_code: ScanCode) -> bool {
let other_player_keymap = match self.selected_player {
Player::Player1 => &self.player2_key_map,
@ -882,6 +943,10 @@ impl ControlsMenu {
self.current = CurrentMenu::ConfirmRebindMenu;
}
}
MenuSelectionResult::Selected(RebindMenuEntry::Reset, _) => {
self.confirm_reset.selected = ConfirmResetMenuEntry::default();
self.current = CurrentMenu::ConfirmResetMenu;
}
_ => {}
},
CurrentMenu::ConfirmRebindMenu => match self.confirm_rebind.tick(controller, state) {
@ -986,6 +1051,19 @@ impl ControlsMenu {
}
}
},
CurrentMenu::ConfirmResetMenu => match self.confirm_reset.tick(controller, state) {
MenuSelectionResult::Selected(ConfirmResetMenuEntry::Yes, _) => {
self.reset_controls(state, ctx)?;
self.update_rebind_menu(state, ctx);
self.input_busy = true;
self.rebind.non_interactive = true;
self.current = CurrentMenu::RebindMenu;
}
MenuSelectionResult::Selected(ConfirmResetMenuEntry::No, _) | MenuSelectionResult::Canceled => {
self.current = CurrentMenu::RebindMenu;
}
_ => {}
},
}
if self.input_busy {
@ -1016,6 +1094,7 @@ impl ControlsMenu {
CurrentMenu::ControllerMenu => self.controller.draw(state, ctx)?,
CurrentMenu::RebindMenu => self.rebind.draw(state, ctx)?,
CurrentMenu::ConfirmRebindMenu => self.confirm_rebind.draw(state, ctx)?,
CurrentMenu::ConfirmResetMenu => self.confirm_reset.draw(state, ctx)?,
}
Ok(())

View File

@ -82,7 +82,7 @@ fn default_true() -> bool {
#[inline(always)]
fn current_version() -> u32 {
16
17
}
#[inline(always)]
@ -250,6 +250,26 @@ impl Settings {
self.player2_controller_button_map.menu_back = self.player2_controller_button_map.shoot;
}
if self.version == 16 {
self.version = 17;
if self.player1_controller_button_map.shoot == PlayerControllerInputType::ButtonInput(Button::East) {
self.player1_controller_button_map.shoot = PlayerControllerInputType::ButtonInput(Button::West);
}
if self.player2_controller_button_map.shoot == PlayerControllerInputType::ButtonInput(Button::East) {
self.player2_controller_button_map.shoot = PlayerControllerInputType::ButtonInput(Button::West);
}
if self.player1_controller_button_map.map == PlayerControllerInputType::ButtonInput(Button::West) {
self.player1_controller_button_map.map = PlayerControllerInputType::ButtonInput(Button::East);
}
if self.player2_controller_button_map.map == PlayerControllerInputType::ButtonInput(Button::West) {
self.player2_controller_button_map.map = PlayerControllerInputType::ButtonInput(Button::East);
}
}
if self.version != initial_version {
log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version);
}
@ -370,7 +390,7 @@ pub struct PlayerKeyMap {
}
#[inline(always)]
fn p1_default_keymap() -> PlayerKeyMap {
pub fn p1_default_keymap() -> PlayerKeyMap {
PlayerKeyMap {
left: ScanCode::Left,
up: ScanCode::Up,
@ -390,7 +410,7 @@ fn p1_default_keymap() -> PlayerKeyMap {
}
#[inline(always)]
fn p2_default_keymap() -> PlayerKeyMap {
pub fn p2_default_keymap() -> PlayerKeyMap {
PlayerKeyMap {
left: ScanCode::Comma,
up: ScanCode::L,
@ -443,11 +463,11 @@ pub fn player_default_controller_button_map() -> PlayerControllerButtonMap {
prev_weapon: PlayerControllerInputType::ButtonInput(Button::LeftShoulder),
next_weapon: PlayerControllerInputType::ButtonInput(Button::RightShoulder),
jump: PlayerControllerInputType::ButtonInput(Button::South),
shoot: PlayerControllerInputType::ButtonInput(Button::East),
shoot: PlayerControllerInputType::ButtonInput(Button::West),
skip: PlayerControllerInputType::AxisInput(Axis::TriggerLeft, AxisDirection::Either),
strafe: PlayerControllerInputType::AxisInput(Axis::TriggerRight, AxisDirection::Either),
inventory: PlayerControllerInputType::ButtonInput(Button::North),
map: PlayerControllerInputType::ButtonInput(Button::West),
map: PlayerControllerInputType::ButtonInput(Button::East),
menu_ok: PlayerControllerInputType::ButtonInput(Button::South),
menu_back: PlayerControllerInputType::ButtonInput(Button::East),
}