Add button bindings to save data, add controls menu; close #6

This commit is contained in:
Dominic Szablewski 2023-08-15 23:40:12 +02:00
parent 0ded93de55
commit b2e3ae80dd
5 changed files with 158 additions and 52 deletions

View file

@ -4,9 +4,9 @@
#include "utils.h"
static const char *button_names[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
[INPUT_KEY_A] = "A",
[INPUT_KEY_B] = "B",

View file

@ -51,7 +51,7 @@ typedef enum {
INPUT_KEY_LEFTBRACKET = 47,
INPUT_KEY_RIGHTBRACKET = 48,
INPUT_KEY_BACKSLASH = 49,
INPUT_KEY_HASH = 50,
INPUT_KEY_HASH = 50,
INPUT_KEY_SEMICOLON = 51,
INPUT_KEY_APOSTROPHE = 52,
INPUT_KEY_TILDE = 53,
@ -108,7 +108,7 @@ typedef enum {
INPUT_KEY_LGUI = 103,
INPUT_KEY_RCTRL = 104,
INPUT_KEY_RSHIFT = 105,
INPUT_KEY_RALT = 106,
INPUT_KEY_RALT = 106,
INPUT_KEY_MAX = 107,

View file

@ -404,8 +404,20 @@ save_t save = {
.has_rapier_class = true, // for testing; should be false in prod
.has_bonus_circuts = true, // for testing; should be false in prod
.highscores_name = {0,0,0,0},
.buttons = {
[A_UP] = {INPUT_KEY_UP, INPUT_GAMEPAD_DPAD_UP},
[A_DOWN] = {INPUT_KEY_DOWN, INPUT_GAMEPAD_DPAD_DOWN},
[A_LEFT] = {INPUT_KEY_LEFT, INPUT_GAMEPAD_DPAD_LEFT},
[A_RIGHT] = {INPUT_KEY_RIGHT, INPUT_GAMEPAD_DPAD_RIGHT},
[A_BRAKE_LEFT] = {INPUT_KEY_C, INPUT_GAMEPAD_L_SHOULDER},
[A_BRAKE_RIGHT] = {INPUT_KEY_V, INPUT_GAMEPAD_R_SHOULDER},
[A_THRUST] = {INPUT_KEY_X, INPUT_GAMEPAD_A},
[A_FIRE] = {INPUT_KEY_Z, INPUT_GAMEPAD_X},
[A_CHANGE_VIEW] = {INPUT_KEY_A, INPUT_GAMEPAD_Y},
},
.highscores_name = {0,0,0,0},
.highscores = {
[RACE_CLASS_VENOM] = {
{
@ -534,7 +546,7 @@ void game_init() {
input_bind(INPUT_LAYER_SYSTEM, INPUT_KEY_X, A_MENU_SELECT);
input_bind(INPUT_LAYER_SYSTEM, INPUT_KEY_RETURN, A_MENU_START);
input_bind(INPUT_LAYER_SYSTEM, INPUT_KEY_ESCAPE, A_MENU_START);
input_bind(INPUT_LAYER_SYSTEM, INPUT_KEY_ESCAPE, A_MENU_QUIT);
// Gamepad
input_bind(INPUT_LAYER_SYSTEM, INPUT_GAMEPAD_DPAD_UP, A_MENU_UP);
@ -552,41 +564,17 @@ void game_init() {
input_bind(INPUT_LAYER_SYSTEM, INPUT_GAMEPAD_A, A_MENU_SELECT);
input_bind(INPUT_LAYER_SYSTEM, INPUT_GAMEPAD_START, A_MENU_START);
// User defined
// TODO: these should be configurable and stored in the save struct
// Keyboard
input_bind(INPUT_LAYER_USER, INPUT_KEY_UP, A_UP);
input_bind(INPUT_LAYER_USER, INPUT_KEY_DOWN, A_DOWN);
input_bind(INPUT_LAYER_USER, INPUT_KEY_LEFT, A_LEFT);
input_bind(INPUT_LAYER_USER, INPUT_KEY_RIGHT, A_RIGHT);
input_bind(INPUT_LAYER_USER, INPUT_KEY_C, A_BRAKE_LEFT);
input_bind(INPUT_LAYER_USER, INPUT_KEY_V, A_BRAKE_RIGHT);
input_bind(INPUT_LAYER_USER, INPUT_KEY_X, A_THRUST);
input_bind(INPUT_LAYER_USER, INPUT_KEY_Z, A_FIRE);
input_bind(INPUT_LAYER_USER, INPUT_KEY_A, A_CHANGE_VIEW);
// Gamepad
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_DPAD_UP, A_UP);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_DPAD_DOWN, A_DOWN);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_DPAD_LEFT, A_LEFT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_DPAD_RIGHT, A_RIGHT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_L_STICK_UP, A_UP);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_L_STICK_DOWN, A_DOWN);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_L_STICK_LEFT, A_LEFT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_L_STICK_RIGHT, A_RIGHT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_L_TRIGGER, A_BRAKE_LEFT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_R_TRIGGER, A_BRAKE_RIGHT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_L_SHOULDER, A_BRAKE_LEFT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_R_SHOULDER, A_BRAKE_RIGHT);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_A, A_THRUST);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_X, A_FIRE);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_Y, A_CHANGE_VIEW);
input_bind(INPUT_LAYER_USER, INPUT_GAMEPAD_SELECT, A_CHANGE_VIEW);
// User defined, loaded from the save struct
for (int action = 0; action < len(save.buttons); action++) {
if (save.buttons[action][0] != INPUT_INVALID) {
input_bind(INPUT_LAYER_USER, save.buttons[action][0], action);
}
if (save.buttons[action][1] != INPUT_INVALID) {
input_bind(INPUT_LAYER_USER, save.buttons[action][1], action);
}
}
game_set_scene(GAME_SCENE_INTRO);

View file

@ -20,15 +20,6 @@
#define SAVE_DATA_MAGIC 0x64736f77
typedef enum {
A_MENU_UP,
A_MENU_DOWN,
A_MENU_LEFT,
A_MENU_RIGHT,
A_MENU_BACK,
A_MENU_SELECT,
A_MENU_START,
A_MENU_QUIT,
A_UP,
A_DOWN,
A_LEFT,
@ -38,6 +29,16 @@ typedef enum {
A_THRUST,
A_FIRE,
A_CHANGE_VIEW,
NUM_GAME_ACTIONS,
A_MENU_UP,
A_MENU_DOWN,
A_MENU_LEFT,
A_MENU_RIGHT,
A_MENU_BACK,
A_MENU_SELECT,
A_MENU_START,
A_MENU_QUIT,
} action_t;
@ -247,6 +248,9 @@ typedef struct {
uint32_t has_rapier_class;
uint32_t has_bonus_circuts;
uint8_t buttons[NUM_GAME_ACTIONS][2];
char highscores_name[4];
highscores_t highscores[NUM_RACE_CLASSES][NUM_CIRCUTS][NUM_HIGHSCORE_TABS];
} save_t;

View file

@ -2,6 +2,7 @@
#include "../system.h"
#include "../mem.h"
#include "../platform.h"
#include "../input.h"
#include "menu.h"
#include "main_menu.h"
@ -133,8 +134,121 @@ static void page_options_init(menu_t *menu) {
// -----------------------------------------------------------------------------
// Options Controls
static const char *button_names[NUM_GAME_ACTIONS][2] = {};
static int control_current_action;
static float await_input_deadline;
void button_capture(void *user, button_t button, int32_t ascii_char) {
if (button == INPUT_INVALID) {
return;
}
menu_t *menu = (menu_t *)user;
if (button == INPUT_KEY_ESCAPE) {
input_capture(NULL, NULL);
menu_pop(menu);
return;
}
int index = button < INPUT_KEY_MAX ? 0 : 1; // joypad or keyboard
// unbind this button if it's bound anywhere
for (int i = 0; i < len(save.buttons); i++) {
if (save.buttons[i][index] == button) {
save.buttons[i][index] = INPUT_INVALID;
}
}
input_capture(NULL, NULL);
input_bind(INPUT_LAYER_USER, button, control_current_action);
save.buttons[control_current_action][index] = button;
save.is_dirty = true;
menu_pop(menu);
}
static void page_options_control_set_draw(menu_t *menu, int data) {
float remaining = await_input_deadline - platform_now();
menu_page_t *page = &menu->pages[menu->index];
char remaining_text[2] = { '0' + (uint8_t)clamp(remaining + 1, 0, 3), '\0'};
vec2i_t pos = vec2i(page->items_pos.x, page->items_pos.y + 24);
ui_draw_text_centered(remaining_text, ui_scaled_pos(page->items_anchor, pos), UI_SIZE_16, UI_COLOR_DEFAULT);
if (remaining <= 0) {
input_capture(NULL, NULL);
menu_pop(menu);
return;
}
}
static void page_options_controls_set_init(menu_t *menu, int data) {
control_current_action = data;
await_input_deadline = platform_now() + 3;
menu_page_t *page = menu_push(menu, "AWAITING INPUT", page_options_control_set_draw);
input_capture(button_capture, menu);
}
static void page_options_control_draw(menu_t *menu, int data) {
menu_page_t *page = &menu->pages[menu->index];
int left = page->items_pos.x + page->block_width - 100;
int right = page->items_pos.x + page->block_width;
int line_y = page->items_pos.y - 20;
vec2i_t left_head_pos = vec2i(left - ui_text_width("KEYBOARD", UI_SIZE_8), line_y);
ui_draw_text("KEYBOARD", ui_scaled_pos(page->items_anchor, left_head_pos), UI_SIZE_8, UI_COLOR_DEFAULT);
vec2i_t right_head_pos = vec2i(right - ui_text_width("JOYSTICK", UI_SIZE_8), line_y);
ui_draw_text("JOYSTICK", ui_scaled_pos(page->items_anchor, right_head_pos), UI_SIZE_8, UI_COLOR_DEFAULT);
line_y += 20;
for (int action = 0; action < NUM_GAME_ACTIONS; action++) {
rgba_t text_color = UI_COLOR_DEFAULT;
if (action == data) {
text_color = UI_COLOR_ACCENT;
}
if (save.buttons[action][0] != INPUT_INVALID) {
const char *name = input_button_to_name(save.buttons[action][0]);
if (!name) {
name = "UNKNWN";
}
vec2i_t pos = vec2i(left - ui_text_width(name, UI_SIZE_8), line_y);
ui_draw_text(name, ui_scaled_pos(page->items_anchor, pos), UI_SIZE_8, text_color);
}
if (save.buttons[action][1] != INPUT_INVALID) {
const char *name = input_button_to_name(save.buttons[action][1]);
if (!name) {
name = "UNKNWN";
}
vec2i_t pos = vec2i(right - ui_text_width(name, UI_SIZE_8), line_y);
ui_draw_text(name, ui_scaled_pos(page->items_anchor, pos), UI_SIZE_8, text_color);
}
line_y += 12;
}
}
static void page_options_controls_init(menu_t *menu) {
menu_page_t *page = menu_push(menu, "TODO", page_options_draw);
menu_page_t *page = menu_push(menu, "CONTROLS", page_options_control_draw);
flags_set(page->layout_flags, MENU_VERTICAL | MENU_FIXED);
page->title_pos = vec2i(-160, -100);
page->title_anchor = UI_POS_MIDDLE | UI_POS_CENTER;
page->items_pos = vec2i(-160, -50);
page->block_width = 320;
page->items_anchor = UI_POS_MIDDLE | UI_POS_CENTER;
// const char *thrust_name = button_name(A_THRUST);
// printf("thrust: %s\n", thrust_name);
menu_page_add_button(page, A_UP, "UP", page_options_controls_set_init);
menu_page_add_button(page, A_DOWN, "DOWN", page_options_controls_set_init);
menu_page_add_button(page, A_LEFT, "LEFT", page_options_controls_set_init);
menu_page_add_button(page, A_RIGHT, "RIGHT", page_options_controls_set_init);
menu_page_add_button(page, A_BRAKE_LEFT, "BRAKE L", page_options_controls_set_init);
menu_page_add_button(page, A_BRAKE_RIGHT, "BRAKE R", page_options_controls_set_init);
menu_page_add_button(page, A_THRUST, "THRUST", page_options_controls_set_init);
menu_page_add_button(page, A_FIRE, "FIRE", page_options_controls_set_init);
menu_page_add_button(page, A_CHANGE_VIEW, "VIEW", page_options_controls_set_init);
}
// -----------------------------------------------------------------------------
@ -178,7 +292,7 @@ static void page_options_video_init(menu_t *menu) {
flags_set(page->layout_flags, MENU_VERTICAL | MENU_FIXED);
page->title_pos = vec2i(-160, -100);
page->title_anchor = UI_POS_MIDDLE | UI_POS_CENTER;
page->items_pos = vec2i(-160, -80);
page->items_pos = vec2i(-160, -60);
page->block_width = 320;
page->items_anchor = UI_POS_MIDDLE | UI_POS_CENTER;