a-game

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

commit 30092d15b10e40929a16ceccc2a108a6906f9520
parent 94cf8fa278e32716a73b27d56628b1c9b3e7ee61
Author: amin <dev@aminmesbah.com>
Date:   Mon,  3 Jun 2019 01:03:47 +0000

Collide with off screen tiles

FossilOrigin-Name: 563ac4b113e53aa6ef1170d8297e578b1e009dab4895f05f00ecb1628890c4a0
Diffstat:
Msrc/am_math.h | 6++++++
Msrc/game.c | 43+++++++++++++++++++++++++------------------
Msrc/world.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 103 insertions(+), 24 deletions(-)

diff --git a/src/am_math.h b/src/am_math.h @@ -53,6 +53,12 @@ internal inline f32 math_rand(f32 min, f32 max) return min + r; } +internal inline bool math_f32_is_i32(f32 x) +{ + bool result = ((i32)x) == x; + return result; +} + internal inline m4 math_m4_init_id() { m4 m = {0}; diff --git a/src/game.c b/src/game.c @@ -61,7 +61,6 @@ internal void game_init(struct GameMemory *game_memory, v2u framebuffer) }, }; - i32 s = -3; i32 f = 3; for (i32 x = s; x <= f; x++) @@ -372,12 +371,12 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga rect tile_search_range = { .min = { - math_floor(math_max(0.0f, player_traversal_occupancy_bb.min.x - 1)), - math_floor(math_max(0.0f, player_traversal_occupancy_bb.min.y - 1)), + math_floor(player_traversal_occupancy_bb.min.x - 1), + math_floor(player_traversal_occupancy_bb.min.y - 1), }, .max = { - math_floor(math_min(ROOM_TILE_DIM_X, player_traversal_occupancy_bb.max.x + 2)), - math_floor(math_min(ROOM_TILE_DIM_Y, player_traversal_occupancy_bb.max.y + 2)), + math_floor(player_traversal_occupancy_bb.max.x + 2), + math_floor(player_traversal_occupancy_bb.max.y + 2), }, }; @@ -392,14 +391,22 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga { for (i32 tile_x = tile_search_range.min.x; tile_x < tile_search_range.max.x; tile_x++) { - assert(tile_x < ROOM_TILE_DIM_X); - assert(tile_y < ROOM_TILE_DIM_Y); - v2 tile_pos = { - tile_x, - tile_y, - }; - - if (tile_is_solid(tiles, tile_pos)) + + struct AbsolutePos tile_pos = world_tile_pos_recanonicalize( + (struct AbsolutePos) { + .room = current_room_i, + .local = (v2) {tile_x, tile_y}, + }); + + // NOTE(amin): pointer alias + u32 *tile_set = tiles; + if (!math_v2i_eq(tile_pos.room, current_room_i)) + { + struct Room *room_containing_tile = world_room_get(game_state->world, tile_pos.room); + tile_set = room_containing_tile->tiles; + } + + if (tile_is_solid(tile_set, tile_pos.local)) { rect tile_aabb = { .min = {tile_x, tile_y}, @@ -407,7 +414,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga }; rect tile_player_sum = math_minkowski_sum_rect_rect(tile_aabb, player->dimensions); - RENDER_COLLISION_DEBUG_QUAD(tile_player_sum, ((v3) {0.8f, 0.4f, 0.4f})); + RENDER_COLLISION_DEBUG_QUAD(tile_aabb, ((v3) {0.8f, 0.4f, 0.4f})); segment tile_sum_b = math_rect_get_edge(tile_player_sum, RECT_EDGE_BOTTOM); segment tile_sum_t = math_rect_get_edge(tile_player_sum, RECT_EDGE_TOP); @@ -419,7 +426,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga v2 norm_l = {-1.0f, 0.0f}; v2 norm_r = {1.0f, 0.0f}; - if (!wall_is_screen_edge(math_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM))) + if (!wall_is_internal(game_state->world, current_room_i, math_rect_get_edge(tile_aabb, RECT_EDGE_BOTTOM))) { struct WallCollision bottom = get_wall_collision(player->pos.local, new_p, tile_sum_b, norm_b); if (bottom.collision_occurred) @@ -436,7 +443,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {1.0f, 0.0f, 0.0f})); } } - if (!wall_is_screen_edge(math_rect_get_edge(tile_aabb, RECT_EDGE_TOP)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_TOP))) + if (!wall_is_internal(game_state->world, current_room_i, math_rect_get_edge(tile_aabb, RECT_EDGE_TOP))) { struct WallCollision top = get_wall_collision(player->pos.local, new_p, tile_sum_t, norm_t); if (top.collision_occurred) @@ -453,7 +460,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {0.0f, 1.0f, 0.0f})); } } - if (!wall_is_screen_edge(math_rect_get_edge(tile_aabb, RECT_EDGE_LEFT)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_LEFT))) + if (!wall_is_internal(game_state->world, current_room_i, math_rect_get_edge(tile_aabb, RECT_EDGE_LEFT))) { struct WallCollision left = get_wall_collision(player->pos.local, new_p, tile_sum_l, norm_l); if (left.collision_occurred) @@ -470,7 +477,7 @@ void game_update_and_render(struct GameMemory *game_memory, struct GameInput *ga RENDER_COLLISION_DEBUG_QUAD(collision, ((v3) {0.0f, 0.0f, 1.0f})); } } - if (!wall_is_screen_edge(math_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT)) && !wall_is_internal(tiles, math_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT))) + if (!wall_is_internal(game_state->world, current_room_i, math_rect_get_edge(tile_aabb, RECT_EDGE_RIGHT))) { struct WallCollision right = get_wall_collision(player->pos.local, new_p, tile_sum_r, norm_r); if (right.collision_occurred) diff --git a/src/world.c b/src/world.c @@ -29,6 +29,40 @@ internal struct AbsolutePos world_pos_recanonicalize(struct AbsolutePos p) return p_final; } +internal inline v2 world_tile_get_sw_corner(v2 tile_center_pos) +{ + v2 tile_sw_corner = { + .x = tile_center_pos.x - (TILE_SIZE * 0.5f), + .y = tile_center_pos.y - (TILE_SIZE * 0.5f), + }; + return tile_sw_corner; +} + +internal inline v2 world_tile_get_center(v2 tile_sw_corner_pos) +{ + v2 tile_center = { + .x = tile_sw_corner_pos.x + (TILE_SIZE * 0.5f), + .y = tile_sw_corner_pos.y + (TILE_SIZE * 0.5f), + }; + return tile_center; +} + +internal struct AbsolutePos world_tile_pos_recanonicalize(struct AbsolutePos tile_p) +{ + v2 tile_center = world_tile_get_center(tile_p.local); + struct AbsolutePos tile_center_canonical_pos = world_pos_recanonicalize( + (struct AbsolutePos) { + .room = tile_p.room, + .local = tile_center, + }); + + struct AbsolutePos tile_canonical_pos = { + .room = tile_center_canonical_pos.room, + .local = world_tile_get_sw_corner(tile_center_canonical_pos.local), + }; + return tile_canonical_pos; +} + internal inline v2i world_room_get_chunk_index(v2i room_i) { // NOTE(amin): truncated integer division here is intentional. We want a @@ -245,15 +279,20 @@ internal bool wall_is_screen_edge(segment wall) return is_screen_edge; } -internal bool wall_is_internal(u32 *tiles, segment wall) +internal bool wall_is_internal(struct World *world, v2i room_i, segment wall) { - assert(tiles); + assert(world); bool is_internal = false; bool wall_is_horizontal = wall.min.y == wall.max.y; bool wall_is_vertical = wall.min.x == wall.max.x; assert(wall_is_vertical || wall_is_horizontal); + assert( + math_f32_is_i32(wall.min.x) + && math_f32_is_i32(wall.min.y) + && math_f32_is_i32(wall.max.x) + && math_f32_is_i32(wall.max.y)); v2 lesser_neighbor = {0}; v2 greater_neighbor = {0}; @@ -261,15 +300,42 @@ internal bool wall_is_internal(u32 *tiles, segment wall) if (wall_is_vertical) { lesser_neighbor = (v2) {wall.min.x - TILE_SIZE, wall.min.y}; - greater_neighbor = wall.min; - is_internal = tile_is_solid(tiles, lesser_neighbor) && tile_is_solid(tiles, greater_neighbor); } else { lesser_neighbor = (v2) {wall.min.x, wall.min.y - TILE_SIZE}; - greater_neighbor = wall.min; - is_internal = tile_is_solid(tiles, lesser_neighbor) && tile_is_solid(tiles, greater_neighbor); } + greater_neighbor = wall.min; + + struct Room *room = world_room_get(world, room_i); + u32 *lesser_tiles = room->tiles; + u32 *greater_tiles = room->tiles; + { + struct AbsolutePos l = world_tile_pos_recanonicalize( + (struct AbsolutePos) { + .room = room_i, + .local = lesser_neighbor, + }); + struct AbsolutePos g = world_tile_pos_recanonicalize( + (struct AbsolutePos) { + .room = room_i, + .local = greater_neighbor, + }); + if (!math_v2i_eq(l.room, room_i)) + { + lesser_neighbor = l.local; + lesser_tiles = world_room_get(world, l.room)->tiles; + } + if (!math_v2i_eq(g.room, room_i)) + { + greater_neighbor = g.local; + greater_tiles = world_room_get(world, g.room)->tiles; + } + } + + assert(lesser_tiles); + assert(greater_tiles); + is_internal = tile_is_solid(lesser_tiles, lesser_neighbor) && tile_is_solid(greater_tiles, greater_neighbor); return is_internal; }