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:
M | src/am_math.h | | | 6 | ++++++ |
M | src/game.c | | | 43 | +++++++++++++++++++++++++------------------ |
M | src/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;
}