a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

commit d4a3bfc002951be50bd276299c12f673e6c4137f
parent 80f148c28218a6a83aafe37fbb2e717eb1645b05
Author: amin <dev@aminmesbah.com>
Date:   Wed, 12 Jun 2019 06:50:40 +0000

Clean up state transitions a bit

FossilOrigin-Name: 501f59f8de68993a25d36b5cd2ad7d970422a9b3c5decfdfb8142db0b2248d5b
Diffstat:
Msrc/game.c | 182++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/game.h | 3+++
2 files changed, 105 insertions(+), 80 deletions(-)

diff --git a/src/game.c b/src/game.c @@ -28,6 +28,42 @@ internal void move_state_print(enum MoveState s) } } +internal bool entity_is_adjacent_to_solid_tiles(rect entity_rect, u32 *tiles, enum Direction dir) +{ + v2 tile_p_to_search_from_min = {0}; + v2 tile_p_to_search_from_max = {0}; + switch(dir) + { + case DIR_RIGHT: + tile_p_to_search_from_min = (v2) {math_ceil(entity_rect.max.x), math_floor(entity_rect.min.y)}; + tile_p_to_search_from_max = (v2) {math_ceil(entity_rect.max.x), math_floor(entity_rect.max.y)}; + break; + case DIR_LEFT: + tile_p_to_search_from_min = (v2) {math_floor(entity_rect.min.x - 1.0f), math_floor(entity_rect.min.y)}; + tile_p_to_search_from_max = (v2) {math_floor(entity_rect.min.x - 1.0f), math_floor(entity_rect.max.y)}; + break; + case DIR_UP: + tile_p_to_search_from_min = (v2) {math_floor(entity_rect.min.x), math_ceil(entity_rect.max.y)}; + tile_p_to_search_from_max = (v2) {math_floor(entity_rect.max.x), math_ceil(entity_rect.max.y)}; + break; + case DIR_DOWN: + tile_p_to_search_from_min = (v2) {math_floor(entity_rect.min.x), math_floor(entity_rect.max.y - 1.0f)}; + tile_p_to_search_from_max = (v2) {math_floor(entity_rect.max.x), math_floor(entity_rect.min.y - 1.0f)}; + break; + default: + assert(false); + break; + } + + bool result = false; + if (tile_is_solid(tiles, tile_p_to_search_from_min) + || tile_is_solid(tiles, tile_p_to_search_from_max)) + { + result = true; + } + return result; +} + internal void game_init(struct GameMemory *game_memory, v2u framebuffer) { assert(sizeof(struct GameState) <= game_memory->buffer_size); @@ -227,104 +263,90 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga player->velocity.x = player->velocity.x * friction; } - // TODO: tune these - if (player->move_state == MOVE_STATE_FALLING) + bool player_is_strictly_within_room = true; { - player->acceleration.y = -acceleration_rate; - } - else if (player->move_state == MOVE_STATE_CLIMBING) - { - bool player_is_still_next_to_wall = true; - rect player_rect = math_rect_from_center_dim(player->pos.local, player->dimensions); - v2 next_tile_top = {0}; - v2 next_tile_bottom = {0}; - if (player->facing == DIR_LEFT) - { - next_tile_top = (v2) {math_floor(player_rect.min.x - 1.0f), math_floor(player_rect.max.y)}; - next_tile_bottom = (v2) {math_floor(player_rect.min.x - 1.0f), math_floor(player_rect.min.y)}; - } - else if (player->facing == DIR_RIGHT) - { - next_tile_top = (v2) {math_ceil(player_rect.max.x), math_floor(player_rect.max.y)}; - next_tile_bottom = (v2) {math_ceil(player_rect.max.x), math_floor(player_rect.min.y)}; - } - else - { - assert(false); - } - renderer_debug_quad_draw( - &game_state->renderer, - (rect) { - .min = next_tile_top, - .max = {next_tile_top.x + TILE_SIZE, next_tile_top.y + TILE_SIZE}, - }, - (v3) {1.0f, 0.0f, 1.0f}); - renderer_debug_quad_draw( - &game_state->renderer, - (rect) { - .min = next_tile_bottom, - .max = {next_tile_bottom.x + TILE_SIZE, next_tile_bottom.y + TILE_SIZE}, - }, - (v3) {1.0f, 0.0f, 1.0f}); - rect player_room_bounds = math_minkowski_diff_rect( (rect) {.min = {0.0f, 0.0f}, .max = {ROOM_TILE_DIM_X, ROOM_TILE_DIM_Y}}, player->dimensions); + player_is_strictly_within_room = math_in_interval_open(player->pos.local.x, player_room_bounds.min.x, player_room_bounds.max.x) + && math_in_interval_open(player->pos.local.y, player_room_bounds.min.y, player_room_bounds.max.y); + } + rect player_rect = math_rect_from_center_dim(player->pos.local, player->dimensions); - if (math_in_interval_open(player->pos.local.x, player_room_bounds.min.x, player_room_bounds.max.x) - && math_in_interval_open(player->pos.local.y, player_room_bounds.min.y, player_room_bounds.max.y)) - { - if (!tile_is_solid(current_room->tiles, next_tile_top) && !tile_is_solid(current_room->tiles, next_tile_bottom)) + // TODO: tune these + switch(player->move_state) + { + case MOVE_STATE_FALLING: + player->acceleration.y = -acceleration_rate; + break; + case MOVE_STATE_GROUNDED: +#if 1 + if (game_input->key_jump) { - player_is_still_next_to_wall = false; + player->acceleration.y = acceleration_rate; + player->move_state = MOVE_STATE_JUMPING; } - } - - if (player_is_still_next_to_wall && player->facing == previous_facing_dir) - { - if (game_input->key_up) +#else + // TODO: do a tile check + if (player_is_strictly_within_room + && entity_is_adjacent_to_solid_tiles(player_rect, current_room->tiles, DIR_DOWN)) { - player->acceleration.y = acceleration_rate; + if (game_input->key_jump) + { + player->acceleration.y = acceleration_rate; + player->move_state = MOVE_STATE_JUMPING; + } + } + else + { + player->move_state = MOVE_STATE_FALLING; } - else if (game_input->key_down) +#endif + break; + case MOVE_STATE_CLIMBING: + if (player_is_strictly_within_room + && player->facing == previous_facing_dir + && entity_is_adjacent_to_solid_tiles(player_rect, current_room->tiles, player->facing)) { - player->acceleration.y = -acceleration_rate; + if (game_input->key_up) + { + player->acceleration.y = acceleration_rate; + } + else if (game_input->key_down) + { + player->acceleration.y = -acceleration_rate; + } + else + { + player->acceleration.y = -acceleration_rate; + } } else { - player->acceleration.y = -acceleration_rate; - player->velocity.y = player->velocity.y * friction; + player->move_state = MOVE_STATE_FALLING; } - } - else + break; + case MOVE_STATE_JUMPING: { - player->move_state = MOVE_STATE_FALLING; - } - } - else if (player->move_state == MOVE_STATE_GROUNDED - || player->move_state == MOVE_STATE_CLIMBING) - { - if (game_input->key_jump) - { - player->acceleration.y = acceleration_rate; - player->move_state = MOVE_STATE_JUMPING; - } - } - else if (player->move_state == MOVE_STATE_JUMPING) - { - if (game_input->key_jump) - { - player->acceleration.y = acceleration_rate; - player->move_state = MOVE_STATE_JUMPING; - } - else - { - player->acceleration.y = -acceleration_rate; - player->move_state = MOVE_STATE_FALLING; + // TODO: give this a real timer + bool jump_timed_out = false; + if (!jump_timed_out && game_input->key_jump) + { + player->acceleration.y = acceleration_rate; + player->move_state = MOVE_STATE_JUMPING; + } + else + { + player->acceleration.y = -acceleration_rate; + player->move_state = MOVE_STATE_FALLING; + } + break; } + default: + assert(false); + break; } - // Semi implicit Euler integration: https://gafferongames.com/post/integration_basics/ player->velocity = math_v2_a(player->velocity, math_v2f_m(player->acceleration, dt)); // TODO: clamp the length of the velocity vector, not each of its components diff --git a/src/game.h b/src/game.h @@ -49,6 +49,8 @@ enum Direction { DIR_RIGHT, DIR_LEFT, + DIR_UP, + DIR_DOWN, }; struct Entity @@ -59,6 +61,7 @@ struct Entity v2 dimensions; enum Direction facing; enum MoveState move_state; + f32 jump_timeout; }; struct GameState