added keyboard input event handling
This commit is contained in:
parent
4ebe759030
commit
6ac2fa6c4f
54
src/fencer.c
54
src/fencer.c
|
@ -1,11 +1,63 @@
|
|||
#include "camera.h"
|
||||
#include "input.h"
|
||||
#include "program.h"
|
||||
#include "spritesheet.h"
|
||||
#include "sprite.h"
|
||||
#include "tilemap.h"
|
||||
#include <assert.h>
|
||||
|
||||
static Spritesheet* spr_player_standing = NULL;
|
||||
static Sprite* player = NULL;
|
||||
static Transform player_trans = IdentityTransform;
|
||||
|
||||
static Level* level = NULL;
|
||||
|
||||
static Vector cam_speed = ZeroVector;
|
||||
|
||||
static
|
||||
void cam_move_h(int val) {
|
||||
cam_speed.x = -val * 0.01f;
|
||||
}
|
||||
static
|
||||
void cam_move_v(int val) {
|
||||
cam_speed.y = val * 0.01f;
|
||||
}
|
||||
|
||||
static
|
||||
void play() {
|
||||
spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128});
|
||||
player = sprite_from_spritesheet(spr_player_standing, 0);
|
||||
sprite_set_origin(player, (Vector){0.5f, 1.0f});
|
||||
player_trans.scale = OneVector;
|
||||
assert(player != NULL && "Player failed to load");
|
||||
|
||||
level = level_load("level_0");
|
||||
assert(level != NULL && "Level failed to load");
|
||||
|
||||
input_add_axis_action(SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, &cam_move_h);
|
||||
input_add_axis_action(SDL_SCANCODE_DOWN, SDL_SCANCODE_UP, &cam_move_v);
|
||||
g_camera.width = 20;
|
||||
}
|
||||
|
||||
static
|
||||
void tick() {
|
||||
g_camera.centre = vaddf(g_camera.centre, cam_speed);
|
||||
}
|
||||
|
||||
static
|
||||
void draw() {
|
||||
level_draw(level);
|
||||
sprite_draw(player, player_trans);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
struct ProgramSettings config = {
|
||||
.target_fps = 0, // unbounded speed
|
||||
.title = "fencer",
|
||||
.view_resolution = {1920, 1080}
|
||||
.view_resolution = {1920, 1080},
|
||||
.on_play = &play,
|
||||
.on_tick = &tick,
|
||||
.on_draw = &draw
|
||||
};
|
||||
return program_run(&config);
|
||||
}
|
||||
|
|
115
src/input.c
Normal file
115
src/input.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include "input.h"
|
||||
#include "debug.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct InputAction {
|
||||
const uint8_t* positive;
|
||||
const uint8_t* negative;
|
||||
int last;
|
||||
InputActionDelegate delegate;
|
||||
} InputAction;
|
||||
|
||||
static InputAction* _actions = NULL;
|
||||
static size_t _actions_len = 0;
|
||||
static size_t _actions_cap = 0;
|
||||
|
||||
static const uint8_t* _keys;
|
||||
|
||||
void input_init() {
|
||||
_actions = malloc(8 * sizeof(InputAction));
|
||||
if(_actions == NULL) {
|
||||
LOG_ERROR("Failed to allocate memory for input actions array");
|
||||
return;
|
||||
}
|
||||
_actions_cap = 8;
|
||||
|
||||
_keys = SDL_GetKeyboardState(NULL);
|
||||
}
|
||||
|
||||
void input_clean() {
|
||||
free(_actions);
|
||||
_actions_len = 0;
|
||||
_actions_cap = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void _key_changed_event(SDL_Event evt) {
|
||||
const uint8_t* keyptr = _keys + evt.key.keysym.scancode;
|
||||
for(InputAction* action = _actions; action < _actions + _actions_len; ++action) {
|
||||
if(keyptr == action->positive || keyptr == action->negative) {
|
||||
int val = *action->positive - *action->negative;
|
||||
if(val != action->last) {
|
||||
action->last = val;
|
||||
action->delegate(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void input_handle_event(SDL_Event event) {
|
||||
switch(event.type) {
|
||||
default:return;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
_key_changed_event(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void _resize_actions_if_needed(size_t needed_amount) {
|
||||
if(_actions_cap > needed_amount)
|
||||
return;
|
||||
|
||||
size_t next_amount = _actions_cap;
|
||||
while(next_amount <= needed_amount) {
|
||||
next_amount *= 2;
|
||||
}
|
||||
|
||||
InputAction* new = realloc(_actions, next_amount);
|
||||
if(new == NULL) {
|
||||
LOG_ERROR("Failed to allocate enough space for adding a new input actions");
|
||||
return;
|
||||
}
|
||||
_actions = new;
|
||||
_actions_cap = next_amount;
|
||||
}
|
||||
|
||||
void input_add_axis_action(SDL_Scancode negative, SDL_Scancode positive, InputActionDelegate delegate) {
|
||||
_resize_actions_if_needed(_actions_len + 1);
|
||||
_actions[_actions_len] = (InputAction){
|
||||
.negative = _keys + negative,
|
||||
.positive = _keys + positive,
|
||||
.delegate = delegate
|
||||
};
|
||||
++_actions_len;
|
||||
}
|
||||
|
||||
void input_add_key_action(SDL_Scancode key, InputActionDelegate delegate) {
|
||||
_resize_actions_if_needed(_actions_len + 1);
|
||||
_actions[_actions_len] = (InputAction) {
|
||||
.negative = NULL,
|
||||
.positive = _keys + key,
|
||||
.delegate = delegate
|
||||
};
|
||||
++_actions_len;
|
||||
}
|
||||
|
||||
static
|
||||
void _remove_element(InputAction* item) {
|
||||
InputAction* next = item + 1;
|
||||
|
||||
if(next < _actions + _actions_len) {
|
||||
memmove(item, next, (_actions + _actions_len) - next);
|
||||
}
|
||||
|
||||
--_actions_len;
|
||||
}
|
||||
|
||||
void input_remove_actions(InputActionDelegate delegate) {
|
||||
for(InputAction* action = _actions; action < _actions + _actions_len; ++action) {
|
||||
if(action->delegate == delegate) {
|
||||
_remove_element(action);
|
||||
}
|
||||
}
|
||||
}
|
19
src/input.h
Normal file
19
src/input.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef _fencer_input_h
|
||||
#define _fencer_input_h
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_scancode.h>
|
||||
#include <SDL2/SDL_keyboard.h>
|
||||
|
||||
typedef void (*InputActionDelegate)(int value);
|
||||
|
||||
extern void input_init();
|
||||
extern void input_clean();
|
||||
|
||||
extern void input_handle_event(SDL_Event event);
|
||||
|
||||
extern void input_add_axis_action(SDL_Scancode negative, SDL_Scancode positive, InputActionDelegate delegate);
|
||||
extern void input_add_key_action(SDL_Scancode key, InputActionDelegate delegate);
|
||||
extern void input_remove_actions(InputActionDelegate delegate);
|
||||
|
||||
#endif // !_fencer_input_h
|
|
@ -1,18 +1,44 @@
|
|||
#include "program.h"
|
||||
#include "tilemap.h"
|
||||
#include "camera.h"
|
||||
#include "sprite.h"
|
||||
#include "time.h"
|
||||
#include "assets.h"
|
||||
#include "debug.h"
|
||||
#include "input.h"
|
||||
#include <assert.h>
|
||||
#include <SDL2/SDL_video.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
|
||||
SDL_Window* g_window;
|
||||
double g_delta_time;
|
||||
double g_frame_start;
|
||||
static double _delta_time;
|
||||
static double _frame_start;
|
||||
static double _game_start_time;
|
||||
|
||||
|
||||
#define INITFLAGS SDL_INIT_EVENTS | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMECONTROLLER
|
||||
|
||||
static inline
|
||||
double tstos(struct timespec ts) {
|
||||
return (double)ts.tv_sec + (double)ts.tv_nsec * 1E-09;
|
||||
}
|
||||
|
||||
struct timespec get_time() {
|
||||
struct timespec ts;
|
||||
timespec_get(&ts, TIME_UTC);
|
||||
return ts;
|
||||
}
|
||||
|
||||
double get_time_s() {
|
||||
return tstos(get_time());
|
||||
}
|
||||
|
||||
int program_run(const struct ProgramSettings* settings) {
|
||||
LOG_INFO("Starting program...");
|
||||
float target_dt = 1.0f/settings->target_fps;
|
||||
if(settings->target_fps <= 0) {
|
||||
target_dt = 0;
|
||||
}
|
||||
_game_start_time = _frame_start = get_time_s();
|
||||
SDL_Init(INITFLAGS);
|
||||
|
||||
g_window = SDL_CreateWindow(
|
||||
|
@ -21,26 +47,41 @@ int program_run(const struct ProgramSettings* settings) {
|
|||
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
|
||||
settings->view_resolution.x,
|
||||
settings->view_resolution.y,
|
||||
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE);
|
||||
SDL_WINDOW_MAXIMIZED | SDL_WINDOW_RESIZABLE);
|
||||
|
||||
render_init(g_window, settings);
|
||||
assets_init();
|
||||
camera_init();
|
||||
input_init();
|
||||
|
||||
Spritesheet* sheet = spritesheet_from_texture("resources/player.png", (IVector){64, 64});
|
||||
Sprite* sprite = sprite_from_spritesheet(sheet);
|
||||
LOG_INFO("settings->on_play");
|
||||
settings->on_play();
|
||||
|
||||
LOG_INFO("Starting program loop");
|
||||
for(;;) {
|
||||
SDL_Delay(1);
|
||||
program_handle_events();
|
||||
sprite_draw(sprite, IdentityTransform);
|
||||
render_present();
|
||||
double current;
|
||||
do {
|
||||
current = get_time_s();
|
||||
_delta_time = current - _frame_start;
|
||||
SDL_Delay(1);
|
||||
program_handle_events();
|
||||
} while(_delta_time <= target_dt);
|
||||
|
||||
_frame_start = current;
|
||||
|
||||
settings->on_tick();
|
||||
settings->on_draw();
|
||||
}
|
||||
|
||||
return 1;
|
||||
LOG_ERROR("Failed to exit");
|
||||
abort();
|
||||
}
|
||||
|
||||
void program_quit() {
|
||||
assets_clean();
|
||||
render_clean();
|
||||
input_clean();
|
||||
SDL_DestroyWindow(g_window);
|
||||
SDL_Quit();
|
||||
exit(0);
|
||||
|
@ -51,6 +92,10 @@ void program_handle_events() {
|
|||
while(SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
default: break;
|
||||
case SDL_KEYUP:
|
||||
case SDL_KEYDOWN:
|
||||
input_handle_event(event);
|
||||
break;
|
||||
case SDL_WINDOWEVENT:
|
||||
if(event.window.windowID == SDL_GetWindowID(g_window)) {
|
||||
program_handle_windowevent(&event.window);
|
||||
|
|
|
@ -6,15 +6,21 @@
|
|||
#include "vmath.h"
|
||||
#include "render.h"
|
||||
|
||||
typedef void(*TickCallback)();
|
||||
typedef void(*PlayCallback)();
|
||||
typedef void(*DrawCallback)();
|
||||
|
||||
struct ProgramSettings {
|
||||
const char* title;
|
||||
IVector view_resolution;
|
||||
int target_fps;
|
||||
|
||||
TickCallback on_tick;
|
||||
PlayCallback on_play;
|
||||
DrawCallback on_draw;
|
||||
};
|
||||
|
||||
extern SDL_Window* g_window;
|
||||
extern double g_delta_time;
|
||||
extern double g_frame_start;
|
||||
|
||||
extern int program_run(const struct ProgramSettings* settings);
|
||||
extern void program_quit();
|
||||
|
|
Loading…
Reference in a new issue