Separate player movement from input event loop.

Wrote a keyboardinput object but decided against using it for the time
being. I'll leave it in if I change my mind.
This commit is contained in:
Linus Probert 2018-05-17 23:14:42 +02:00
parent c4dc8382a9
commit 2813a571e4
11 changed files with 299 additions and 60 deletions

View File

@ -153,6 +153,7 @@ add_executable(breakhack
src/menu
src/collisions
src/keyboard
src/keyboardinput
src/mixer
src/io_util
src/physfsrwops
@ -215,6 +216,10 @@ IF (CMOCKA_FOUND)
add_executable(test_hashtable test/test_hashtable src/hashtable src/util)
target_link_libraries(test_hashtable ${CMOCKA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
add_test(test_hashtable test_hashtable)
add_executable(test_keyboardinput test/test_keyboardinput src/keyboardinput src/keyboard)
target_link_libraries(test_keyboardinput ${CMOCKA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
add_test(test_keyboardinput test_keyboardinput)
ENDIF (CMOCKA_FOUND )
# LINT:

View File

@ -19,12 +19,9 @@
#include "keyboard.h"
#include "util.h"
bool
keyboard_direction_press(Direction dir, SDL_Event *event)
static bool
extract_key(Direction dir, SDL_Event *event)
{
if (event->type != SDL_KEYDOWN)
return false;
Uint32 key = event->key.keysym.sym;
switch (dir) {
case UP:
@ -48,6 +45,24 @@ keyboard_direction_press(Direction dir, SDL_Event *event)
}
}
bool
keyboard_direction_press(Direction dir, SDL_Event *event)
{
if (event->type != SDL_KEYDOWN)
return false;
return extract_key(dir, event);
}
bool
keyboard_direction_release(Direction dir, SDL_Event *event)
{
if (event->type != SDL_KEYUP)
return false;
return extract_key(dir, event);
}
bool
keyboard_press(Uint32 key, SDL_Event *event)
{
@ -57,6 +72,15 @@ keyboard_press(Uint32 key, SDL_Event *event)
return key == (Uint32) event->key.keysym.sym;
}
bool
keyboard_release(Uint32 key, SDL_Event *event)
{
if (event->type != SDL_KEYUP)
return false;
return key == (Uint32) event->key.keysym.sym;
}
bool
keyboard_mod_press(Uint32 key, Uint32 mod, SDL_Event *event)
{

View File

@ -26,9 +26,15 @@
bool
keyboard_direction_press(Direction, SDL_Event*);
bool
keyboard_direction_release(Direction, SDL_Event*);
bool
keyboard_press(Uint32 key, SDL_Event*);
bool
keyboard_release(Uint32 key, SDL_Event*);
bool
keyboard_mod_press(Uint32 key, Uint32 mod, SDL_Event*);

83
src/keyboardinput.c Normal file
View File

@ -0,0 +1,83 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "keyboardinput.h"
#include "keyboard.h"
#include "vector2d.h"
void
keyboardinput_init(KeyboardInput *input)
{
input->currentState = 0;
input->lastState = 0;
}
void
keyboardinput_handle_event(KeyboardInput *input, SDL_Event *event)
{
if (keyboard_direction_press(UP, event)) {
input->currentState |= KEY_UP;
} else if (keyboard_direction_press(DOWN, event)) {
input->currentState |= KEY_DOWN;
} else if (keyboard_direction_press(LEFT, event)) {
input->currentState |= KEY_LEFT;
} else if (keyboard_direction_press(RIGHT, event)) {
input->currentState |= KEY_RIGHT;
} else if (keyboard_press(SDLK_0, event)) {
input->currentState |= KEY_NUM1;
}
for (int i = SDLK_0; i <= SDLK_9; ++i) {
if (keyboard_press(i, event))
input->currentState |= (1 << i);
}
if (keyboard_direction_release(UP, event)) {
input->currentState &= ~KEY_UP;
} else if (keyboard_direction_release(DOWN, event)) {
input->currentState &= ~KEY_DOWN;
} else if (keyboard_direction_release(LEFT, event)) {
input->currentState &= ~KEY_LEFT;
} else if (keyboard_direction_release(RIGHT, event)) {
input->currentState &= ~KEY_RIGHT;
} else if (keyboard_release(SDLK_0, event)) {
input->currentState &= ~KEY_NUM1;
}
for (int i = SDLK_0; i <= SDLK_9; ++i) {
if (keyboard_release(i, event))
input->currentState &= ~(1 << i);
}
}
bool
key_is_pressed(KeyboardInput *input, Uint64 key)
{
return (input->currentState & key) && !(input->lastState & key);
}
bool
key_is_released(KeyboardInput *input, Uint64 key)
{
return (input->lastState & key) && !(input->currentState & key);
}
bool
key_is_down(KeyboardInput *input, Uint64 key)
{
return input->currentState & key;
}

68
src/keyboardinput.h Normal file
View File

@ -0,0 +1,68 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEYBOARDINPUT_H_
#define KEYBOARDINPUT_H_
#include <SDL.h>
#include <stdbool.h>
#define KEY_LEFT 1
#define KEY_RIGHT 2
#define KEY_UP 4
#define KEY_DOWN 8
#define KEY_NUM0 16
#define KEY_NUM1 32
#define KEY_NUM2 64
#define KEY_NUM3 128
#define KEY_NUM4 256
#define KEY_NUM5 512
#define KEY_NUM6 1024
#define KEY_NUM7 2048
#define KEY_NUM8 4096
#define KEY_NUM9 8192
typedef struct KeyboardState {
bool dir_left;
bool dir_right;
bool dir_up;
bool dir_down;
} KeyboardState;
typedef struct KeyboardInput {
Uint64 currentState;
Uint64 lastState;
} KeyboardInput;
void
keyboardinput_init(KeyboardInput *);
void
keyboardinput_handle_event(KeyboardInput *, SDL_Event*);
bool
key_is_pressed(KeyboardInput *, Uint64 key);
bool
key_is_released(KeyboardInput *, Uint64 key);
bool
key_is_down(KeyboardInput *, Uint64 key);
#endif // KEYBOARDINPUT_H_

View File

@ -412,8 +412,6 @@ handle_events(void)
gPlayer->handle_event(gPlayer,
gRoomMatrix,
&event);
camera_follow_position(gCamera, &gPlayer->sprite->pos);
map_set_current_room(gMap, &gPlayer->sprite->pos);
roommatrix_handle_event(gRoomMatrix, &event);
skillbar_handle_event(gSkillBar, &event);
} else if (gGameState == MENU) {
@ -496,8 +494,10 @@ run_game(void)
particle_engine_update(deltaTime);
actiontextbuilder_update(&updateData);
map_update(&updateData);
player_update(&updateData);
camera_follow_position(gCamera, &gPlayer->sprite->pos);
map_set_current_room(gMap, &gPlayer->sprite->pos);
map_update(&updateData);
roommatrix_update_with_player(gRoomMatrix, gPlayer);
if (currentTurn == PLAYER) {

View File

@ -401,6 +401,9 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
void
monster_render(Monster *m, Camera *cam)
{
if (m->stats.hp <= 0)
return;
sprite_render(m->sprite, cam);
if (m->stateIndicator.displayCount > 0)
sprite_render(m->stateIndicator.sprite, cam);

View File

@ -209,41 +209,21 @@ player_sip_health(Player *player)
}
static void
handle_movement_input(Player *player, RoomMatrix *matrix, SDL_Event *event)
handle_next_move(Player *player, RoomMatrix *matrix)
{
static unsigned int step = 1;
Vector2d direction = VECTOR2D_NODIR;
if (!vector2d_equals(player->nextDirection, VECTOR2D_NODIR))
move(player, matrix, player->nextDirection);
if (keyboard_direction_press(LEFT, event))
direction = VECTOR2D_LEFT;
if (keyboard_direction_press(RIGHT, event))
direction = VECTOR2D_RIGHT;
if (keyboard_direction_press(UP, event))
direction = VECTOR2D_UP;
if (keyboard_direction_press(DOWN, event))
direction = VECTOR2D_DOWN;
map_room_modifier_player_effect(player, matrix, &player->nextDirection, move);
if (!vector2d_equals(direction, VECTOR2D_NODIR))
move(player, matrix, direction);
map_room_modifier_player_effect(player, matrix, &direction, move);
#ifdef DEBUG
if (keyboard_mod_press(SDLK_SPACE, KMOD_CTRL, event)) {
Position pos = player->sprite->pos;
pos.x += 8;
pos.y += 8;
particle_engine_bloodspray(pos, (Dimension) { 8, 8 }, 200);
player->stats.hp = 0;
}
#endif // DEBUG
if (!vector2d_equals(VECTOR2D_NODIR, direction)) {
if (!vector2d_equals(VECTOR2D_NODIR, player->nextDirection)) {
player->sprite->clip.x = 16*step;
++step;
step = step % 4;
}
player->nextDirection = VECTOR2D_NODIR;
}
static void
@ -293,8 +273,8 @@ check_skill_activation(Player *player, RoomMatrix *matrix, SDL_Event *event)
}
}
static bool
check_skill_trigger(Player *player, RoomMatrix *matrix, SDL_Event *event)
static void
check_skill_trigger(Player *player, RoomMatrix *matrix)
{
int activeSkill = -1;
for (int i = 0; i < PLAYER_SKILL_COUNT; ++i) {
@ -305,26 +285,34 @@ check_skill_trigger(Player *player, RoomMatrix *matrix, SDL_Event *event)
}
if (activeSkill < 0)
return false;
return;
Vector2d dir;
if (keyboard_direction_press(UP, event))
dir = VECTOR2D_UP;
else if (keyboard_direction_press(DOWN, event))
dir = VECTOR2D_DOWN;
else if (keyboard_direction_press(LEFT, event))
dir = VECTOR2D_LEFT;
else if (keyboard_direction_press(RIGHT, event))
dir = VECTOR2D_RIGHT;
else
return false;
SkillData skillData = { player, matrix, dir };
if (vector2d_equals(player->nextDirection, VECTOR2D_NODIR))
return;
SkillData skillData = { player, matrix, player->nextDirection };
use_skill(player->skills[activeSkill], &skillData);
return true;
player->nextDirection = VECTOR2D_NODIR;
}
static void
read_player_next_direction(Player *player, SDL_Event *event)
{
player->nextDirection = VECTOR2D_NODIR;
if (keyboard_direction_press(LEFT, event))
player->nextDirection = VECTOR2D_LEFT;
if (keyboard_direction_press(RIGHT, event))
player->nextDirection = VECTOR2D_RIGHT;
if (keyboard_direction_press(UP, event))
player->nextDirection = VECTOR2D_UP;
if (keyboard_direction_press(DOWN, event))
player->nextDirection = VECTOR2D_DOWN;
}
static void
handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event)
{
@ -338,8 +326,7 @@ handle_player_input(Player *player, RoomMatrix *matrix, SDL_Event *event)
return;
check_skill_activation(player, matrix, event);
if (!check_skill_trigger(player, matrix, event))
handle_movement_input(player, matrix, event);
read_player_next_direction(player, event);
}
Player*
@ -360,6 +347,7 @@ player_create(class_t class, SDL_Renderer *renderer)
player->state = ALIVE;
player->projectiles = linkedlist_create();
player->animationTimer = timer_create();
player->nextDirection = VECTOR2D_NODIR;
for (size_t i = 0; i < PLAYER_SKILL_COUNT; ++i) {
player->skills[i] = NULL;
@ -476,6 +464,10 @@ player_reset_steps(Player *p)
void player_update(UpdateData *data)
{
Player *player = data->player;
check_skill_trigger(player, data->matrix);
handle_next_move(player, data->matrix);
if (player->state == FALLING && player->stats.hp > 0) {
if (!timer_started(player->animationTimer)) {
timer_start(player->animationTimer);

View File

@ -63,6 +63,7 @@ typedef struct Player_t {
state_t state;
Skill *skills[PLAYER_SKILL_COUNT];
Timer *animationTimer;
Vector2d nextDirection;
void (*handle_event)(struct Player_t*, RoomMatrix*, SDL_Event*);
} Player;

View File

@ -44,14 +44,7 @@ pointer_handle_event(Pointer *p, SDL_Event *event)
// Compensate for a small offset in the sprite
p->sprite->pos.x = event->motion.x - 6;
p->sprite->pos.y = event->motion.y - 6;
//debug("Pointer pos: %dx%d", p->sprite->pos.x, p->sprite->pos.y);
}
#ifdef DEBUG
if (event->type == SDL_MOUSEBUTTONDOWN) {
Dimension dim = { 10, 10 };
particle_engine_sparkle(p->sprite->pos, dim);
}
#endif // DEBUG
}
void

64
test/test_keyboardinput.c Normal file
View File

@ -0,0 +1,64 @@
/*
* BreakHack - A dungeone crawler RPG
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <setjmp.h>
#include <cmocka.h>
#include "../src/keyboardinput.h"
static KeyboardInput input = { 0, 0 };
static void
test_keypress(void **state)
{
(void) state;
input.lastState = 0;
input.currentState = KEY_UP;
assert_true(key_is_pressed(&input, KEY_UP));
}
static void
test_keyrelease(void **state)
{
(void) state;
input.lastState = KEY_UP;
input.currentState = 0;
assert_true(key_is_released(&input, KEY_UP));
}
static void
test_keydown(void **state)
{
(void) state;
input.currentState = KEY_UP;
assert_true(key_is_down(&input, KEY_UP));
}
int main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_keypress),
cmocka_unit_test(test_keyrelease),
cmocka_unit_test(test_keydown),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}