diff --git a/README.md b/README.md index 691c2b8..5bfcfd0 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ The final build order should have an additional game module: `handmade`, that wi ## Milestone -Day 48 : Line Segment Intersection Collisions +Day 49 : Debugging Canonical Coordinatescl Features Done so far: diff --git a/project/engine/engine.cpp b/project/engine/engine.cpp index 0b89392..7da36a2 100644 --- a/project/engine/engine.cpp +++ b/project/engine/engine.cpp @@ -441,10 +441,7 @@ void player_init( hh::Player* player, hh::GameState* gs ) entity->kind = hh::EntityKind_Hero; - entity->position.tile_x = 4; - entity->position.tile_y = 4; - entity->position.rel_pos.x = 0.f; - entity->position.rel_pos.y = 0.f; + entity->position = gs->spawn_pos; entity->velocity = {}; @@ -569,7 +566,9 @@ void update_player( hh::Player* player, f32 delta_time, World* world, hh::GameSt f32 player_half_width = entity->width / 2.f; f32 player_quarter_height = entity->height / 4.f; - f32 move_accel = 36.f; +// f32 move_accel = 36.f; + f32 move_accel = 200.f; + if ( actions->sprint ) { move_accel = 94.f; @@ -702,52 +701,91 @@ void update_player( hh::Player* player, f32 delta_time, World* world, hh::GameSt } else { - TileMapPos new_pos = { + TileMapPos new_pos = recannonicalize_position( tile_map, { new_player_pos.x, new_player_pos.y, old_pos.tile_x, old_pos.tile_y, old_pos.tile_z - }; - new_pos = recannonicalize_position( tile_map, new_pos ); - - s32 min_tile_x = min( old_pos.tile_x, new_pos.tile_x ); - s32 min_tile_y = min( old_pos.tile_y, new_pos.tile_y ); - - s32 max_tile_x = max( old_pos.tile_x, new_pos.tile_x ); - s32 max_tile_y = max( old_pos.tile_y, new_pos.tile_y ); - - TileMapPos best_position = old_pos; - - f32 min_intersection_delta = 1.0f; - for ( s32 tile_y = min_tile_y; tile_y <= max_tile_y; ++ tile_y ) - for ( s32 tile_x = min_tile_x; tile_x <= max_tile_x; ++ tile_x ) + }); + TileMapPos best_position = old_pos; + f32 min_intersection_delta = 1.0f; + + if (0) { - TileMapPos test_tile_pos = centered_tile_point( tile_x, tile_y, old_pos.tile_z ); - s32 tile_value = TileMap_get_tile_value( tile_map, test_tile_pos ); - if ( ! TileMap_is_tile_value_empty( tile_value ) ) + s32 min_tile_x = min( old_pos.tile_x, new_pos.tile_x ); + s32 min_tile_y = min( old_pos.tile_y, new_pos.tile_y ); + + s32 max_tile_x = max( old_pos.tile_x, new_pos.tile_x ); + s32 max_tile_y = max( old_pos.tile_y, new_pos.tile_y ); + + for ( s32 tile_y = min_tile_y; tile_y <= max_tile_y; ++ tile_y ) + for ( s32 tile_x = min_tile_x; tile_x <= max_tile_x; ++ tile_x ) { - Vec2 tile_xy_in_meters = Vec2 { tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }; + TileMapPos test_tile_pos = centered_tile_point( tile_x, tile_y, old_pos.tile_z ); + s32 tile_value = TileMap_get_tile_value( tile_map, test_tile_pos ); + if ( ! TileMap_is_tile_value_empty( tile_value ) ) + { + Vec2 tile_xy_in_meters = Vec2 { tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }; + + Vec2 min_corner = -0.5f * tile_xy_in_meters; + Vec2 max_corner = 0.5f * tile_xy_in_meters; + + Vec2 rel_old_pos = subtract( old_pos, test_tile_pos ).rel_pos; + Vec2 rel_old_pos_inv = { rel_old_pos.y, rel_old_pos.x }; + Vec2 vel_inv = { entity->velocity.y, entity->velocity.x }; + + test_wall( min_corner.x, rel_old_pos, min_corner.y, max_corner.y, entity->velocity, & min_intersection_delta ); + test_wall( max_corner.x, rel_old_pos, min_corner.y, max_corner.y, entity->velocity, & min_intersection_delta ); + test_wall( min_corner.y, rel_old_pos_inv, min_corner.x, max_corner.x, vel_inv, & min_intersection_delta ); + test_wall( max_corner.y, rel_old_pos_inv, min_corner.x, max_corner.x, vel_inv, & min_intersection_delta ); + } + } + } + else + { + s32 tile_delta_x = sign( new_pos.tile_x - old_pos.tile_x ); + s32 tile_delta_y = sign( new_pos.tile_y - old_pos.tile_y ); + + for ( s32 tile_y = old_pos.tile_y; ; tile_y += tile_delta_y ) + { + for ( s32 tile_x = old_pos.tile_x; ; tile_x += tile_delta_x ) + { + TileMapPos test_tile_pos = centered_tile_point( tile_x, tile_y, old_pos.tile_z ); + s32 tile_value = TileMap_get_tile_value( tile_map, test_tile_pos ); + + local_persist TileChunkPosition last_chunk = {}; + TileChunkPosition curr_chunk = get_tile_chunk_position_for(tile_map, old_pos.tile_x, old_pos.tile_y, old_pos.tile_z ); + + if ( ! TileMap_is_tile_value_empty( tile_value ) ) + { + Vec2 tile_xy_in_meters = Vec2 { tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }; + + Vec2 min_corner = -0.5f * tile_xy_in_meters; + Vec2 max_corner = 0.5f * tile_xy_in_meters; + + Vec2 rel_old_pos = subtract( old_pos, test_tile_pos ).rel_pos; + Vec2 rel_old_pos_inv = { rel_old_pos.y, rel_old_pos.x }; + Vec2 vel_inv = { entity->velocity.y, entity->velocity.x }; + + test_wall( min_corner.x, rel_old_pos, min_corner.y, max_corner.y, entity->velocity, & min_intersection_delta ); + test_wall( max_corner.x, rel_old_pos, min_corner.y, max_corner.y, entity->velocity, & min_intersection_delta ); + test_wall( min_corner.y, rel_old_pos_inv, min_corner.x, max_corner.x, vel_inv, & min_intersection_delta ); + test_wall( max_corner.y, rel_old_pos_inv, min_corner.x, max_corner.x, vel_inv, & min_intersection_delta ); + } + + if ( tile_x == new_pos.tile_x ) + break; + } - Vec2 min_corner = -0.5f * tile_xy_in_meters; - Vec2 max_corner = 0.5f * tile_xy_in_meters; - - Vec2 rel_old_pos = subtract( old_pos, test_tile_pos ).rel_pos; - Vec2 rel_old_pos_inv = { rel_old_pos.y, rel_old_pos.x }; - Vec2 vel_inv = { entity->velocity.y, entity->velocity.x }; - - test_wall( min_corner.x, rel_old_pos, min_corner.y, max_corner.y, entity->velocity, & min_intersection_delta ); - test_wall( max_corner.x, rel_old_pos, min_corner.y, max_corner.y, entity->velocity, & min_intersection_delta ); - test_wall( min_corner.y, rel_old_pos_inv, min_corner.x, max_corner.x, vel_inv, & min_intersection_delta ); - test_wall( max_corner.y, rel_old_pos_inv, min_corner.x, max_corner.x, vel_inv, & min_intersection_delta ); + if ( tile_y == new_pos.tile_y ) + break; } } new_player_pos = { old_pos.rel_pos.x, old_pos.rel_pos.y }; new_player_pos += entity->velocity * min_intersection_delta; - - new_pos = { + new_pos = recannonicalize_position( tile_map, { new_player_pos.x, new_player_pos.y, old_pos.tile_x, old_pos.tile_y, old_pos.tile_z - }; - new_pos = recannonicalize_position( tile_map, new_pos ); + }); entity->position = new_pos; } @@ -922,7 +960,10 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* state->game_memory.persistent = rcast(Byte*, memory->persistent) + state->game_memory.persistent_size; state->game_memory.transient_size = memory->transient_size / Memory::game_memory_factor; state->game_memory.transient = rcast(Byte*, memory->transient) + state->game_memory.transient_size; - + + hh::GameState* gs = rcast( hh::GameState*, state->game_memory.persistent ); + assert( sizeof(hh::GameState) <= state->game_memory.persistent_size ); + World* world; // World setup @@ -965,10 +1006,10 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* world->tiles_per_screen_x = 17; world->tiles_per_screen_y = 9; - u32 screen_x = 0; - u32 screen_y = 0; + s32 screen_x = -10; + s32 screen_y = -10; u32 rng_index = 0; - + b32 door_left = false; b32 door_right = false; b32 door_top = false; @@ -978,7 +1019,7 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* u32 abs_tile_z = 0; - for ( u32 screen_index = 0; screen_index < 100; ++ screen_index ) + for ( u32 screen_index = 0; screen_index <= 100; ++ screen_index ) { // TODO(Ed) : We need a proper RNG. assert( rng_index < array_count(RNG_Table) ) @@ -1014,6 +1055,9 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* { door_top = true; } + + local_persist TileChunkPosition last_chunk = {}; + s32 chunk_index = 0; for (s32 tile_y = 0; tile_y < world->tiles_per_screen_y; ++ tile_y ) { @@ -1021,6 +1065,12 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* { s32 abs_tile_x = screen_x * world->tiles_per_screen_x + tile_x; s32 abs_tile_y = screen_y * world->tiles_per_screen_y + tile_y; + + do_once() + { + gs->spawn_pos.tile_x = abs_tile_x + 4; + gs->spawn_pos.tile_y = abs_tile_y + 4; + } s32 tile_value = 1; @@ -1063,9 +1113,22 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* } } + last_chunk = get_tile_chunk_position_for( tile_map, abs_tile_x, abs_tile_y, abs_tile_z ); + chunk_index = + last_chunk.z * tile_map->tile_chunks_num_y * tile_map->tile_chunks_num_x + + last_chunk.y * tile_map->tile_chunks_num_x + + last_chunk.x; + // u32 tile_value = tile_x == tile_y && tile_y % 2 ? 1 : 0; TileMap_set_tile_value( & state->world_arena, world->tile_map, abs_tile_x, abs_tile_y, abs_tile_z, tile_value ); } + + s32 something = false; + something++; + if ( something ) + { + something--; + } } door_left = door_right; @@ -1107,9 +1170,6 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* } } - hh::GameState* gs = rcast( hh::GameState*, state->game_memory.persistent ); - assert( sizeof(hh::GameState) <= state->game_memory.persistent_size ); - // Personally made assets { StrPath path_test_bg {}; @@ -1198,9 +1258,6 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* using hh::FacingDirection_Front; -// gs->player_1 = {}; -// gs->player_2 = {}; - gs->camera_assigned_entity_id = gs->player_1.entity_id; } @@ -1419,10 +1476,17 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back s32 tile_id = TileMap_get_tile_value( tile_map, col, row, gs->camera_pos.tile_z ); f32 color[3] = { 0.15f, 0.15f, 0.15f }; - - if ( tile_id > 1 || (entity_followed && row == entity_followed->position.tile_y && col == entity_followed->position.tile_x) ) + + if ( tile_id > 1 || tile_id == 0 || (entity_followed && row == entity_followed->position.tile_y && col == entity_followed->position.tile_x) ) // if ( tile_id > 1 ) { + if ( tile_id == 0 ) + { + color[0] = 0.88f; + color[1] = 0.22f; + color[2] = 0.77f; + } + if ( tile_id == 2 ) { color[0] = 0.42f; @@ -1448,9 +1512,9 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back color[1] = 0.3f; color[2] = 0.3f; } - + f32 tile_size_in_pixels = scast(f32, world->tile_size_in_pixels); - + Vec2 tile_pixel_size = Vec2 { tile_size_in_pixels * 0.5f, tile_size_in_pixels * 0.5f } * 0.9f; Pos2 center { screen_center.x + scast(f32, relative_col) * tile_size_in_pixels - gs->camera_pos.rel_pos.x * world->tile_meters_to_pixels, @@ -1458,7 +1522,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back }; Pos2 min = center - cast( Pos2, tile_pixel_size ); Pos2 max = center + cast( Pos2, tile_pixel_size ); - + draw_rectangle( back_buffer , min, max , color[0], color[1], color[2] ); diff --git a/project/engine/tile_map.cpp b/project/engine/tile_map.cpp index 52d4ef5..89c7fc9 100644 --- a/project/engine/tile_map.cpp +++ b/project/engine/tile_map.cpp @@ -7,7 +7,7 @@ NS_ENGINE_BEGIN inline TileMapPos subtract( TileMapPos pos_a, TileMapPos pos_b ) { - TileMapPos result { + TileMapPos result = { pos_a.rel_pos - pos_b.rel_pos, pos_a.tile_x - pos_b.tile_x, @@ -16,6 +16,7 @@ TileMapPos subtract( TileMapPos pos_a, TileMapPos pos_b ) // TODO(Ed) : Think about how to handle z... pos_a.tile_z - pos_b.tile_z }; + return result; } @@ -52,6 +53,13 @@ TileMapPos recannonicalize_position( TileMap* tile_map, TileMapPos pos ) cannonicalize_coord( tile_map, & result.tile_y, & result.rel_pos.y ); return result; } + +inline +void offset( TileMap* tile_map, TileMapPos& map_pos, Vec2 rel_offset ) +{ + map_pos.rel_pos += rel_offset; + map_pos = recannonicalize_position( tile_map, map_pos); +} inline u32 TileChunk_get_tile_value( TileChunk* tile_chunk, TileMap* tile_map, s32 x, s32 y ) @@ -77,18 +85,20 @@ void TileChunk_set_tile_value( TileChunk* tile_chunk, TileMap* tile_map, s32 x, } inline -TileChunk* TileMap_get_chunk( TileMap* tile_map, s32 tile_chunk_x, s32 tile_chunk_y, s32 tile_chunk_z ) +TileChunk* TileMap_get_chunk( TileMap* tile_map, TileChunkPosition chunk_pos ) { TileChunk* chunk = nullptr; - if ( tile_chunk_x >= 0 && tile_chunk_x < scast(s32, tile_map->tile_chunks_num_x) - && tile_chunk_y >= 0 && tile_chunk_y < scast(s32, tile_map->tile_chunks_num_y) - && tile_chunk_z >= 0 && tile_chunk_z < scast(s32, tile_map->tile_chunks_num_z) ) + if ( chunk_pos.x >= 0 && chunk_pos.x < tile_map->tile_chunks_num_x + && chunk_pos.y >= 0 && chunk_pos.y < tile_map->tile_chunks_num_y + && chunk_pos.z >= 0 && chunk_pos.z < tile_map->tile_chunks_num_z ) { chunk = & tile_map->chunks[ - tile_chunk_z * tile_map->tile_chunks_num_y * tile_map->tile_chunks_num_x - + tile_chunk_y * tile_map->tile_chunks_num_x - + tile_chunk_x ]; + chunk_pos.z * tile_map->tile_chunks_num_y * tile_map->tile_chunks_num_x + + chunk_pos.y * tile_map->tile_chunks_num_x + + chunk_pos.x ]; + + return chunk; } return chunk; @@ -100,11 +110,24 @@ TileChunkPosition get_tile_chunk_position_for( TileMap* tile_map, s32 abs_tile_x assert( tile_map != nullptr ); TileChunkPosition chunk_pos {}; - chunk_pos.tile_chunk_x = abs_tile_x >> tile_map->chunk_shift; - chunk_pos.tile_chunk_y = abs_tile_y >> tile_map->chunk_shift; - chunk_pos.tile_chunk_z = abs_tile_z; - chunk_pos.tile_x = abs_tile_x & tile_map->chunk_mask; - chunk_pos.tile_y = abs_tile_y & tile_map->chunk_mask; + chunk_pos.x = abs_tile_x >> tile_map->chunk_shift; + chunk_pos.y = abs_tile_y >> tile_map->chunk_shift; + chunk_pos.z = abs_tile_z; + + // Correct negative values + s32 neg_mask = (1 << (sizeof(s32) * 8 - 1)); + s32 is_neg_x = (chunk_pos.x & neg_mask) < 0; + s32 is_neg_y = (chunk_pos.y & neg_mask) < 0; + s32 offset_x = is_neg_x * tile_map->tile_chunks_num_x; + s32 offset_y = is_neg_y * tile_map->tile_chunks_num_y; + chunk_pos.x = offset_x + chunk_pos.x; + chunk_pos.y = offset_y + chunk_pos.y; + +// chunk_pos.tile_x = (abs_tile_x * (-1 * is_neg_x)) & tile_map->chunk_mask; +// chunk_pos.tile_y = (abs_tile_y * (-1 * is_neg_y)) & tile_map->chunk_mask; + + chunk_pos.tile_x = abs_tile_x & tile_map->chunk_mask; + chunk_pos.tile_y = abs_tile_y & tile_map->chunk_mask; return chunk_pos; } @@ -117,7 +140,7 @@ u32 TileMap_get_tile_value( TileMap* tile_map, s32 tile_x, s32 tile_y, s32 tile_ s32 value = 0; TileChunkPosition chunk_pos = get_tile_chunk_position_for( tile_map, tile_x, tile_y, tile_z ); - TileChunk* chunk = TileMap_get_chunk( tile_map, chunk_pos.tile_chunk_x, chunk_pos.tile_chunk_y, chunk_pos.tile_chunk_z ); + TileChunk* chunk = TileMap_get_chunk( tile_map, chunk_pos ); if ( chunk && chunk->tiles ) value = TileChunk_get_tile_value( chunk, tile_map, chunk_pos.tile_x, chunk_pos.tile_y ); @@ -155,7 +178,7 @@ internal void TileMap_set_tile_value( MemoryArena* arena, TileMap* tile_map, s32 abs_tile_x, s32 abs_tile_y, s32 abs_tile_z, s32 value ) { TileChunkPosition chunk_pos = get_tile_chunk_position_for( tile_map, abs_tile_x, abs_tile_y, abs_tile_z ); - TileChunk* chunk = TileMap_get_chunk( tile_map, chunk_pos.tile_chunk_x, chunk_pos.tile_chunk_y, chunk_pos.tile_chunk_z ); + TileChunk* chunk = TileMap_get_chunk( tile_map, chunk_pos ); assert( chunk != nullptr ); diff --git a/project/engine/tile_map.hpp b/project/engine/tile_map.hpp index e154171..eb29480 100644 --- a/project/engine/tile_map.hpp +++ b/project/engine/tile_map.hpp @@ -23,9 +23,9 @@ struct TileChunk */ struct TileChunkPosition { - s32 tile_chunk_x; - s32 tile_chunk_y; - s32 tile_chunk_z; + s32 x; + s32 y; + s32 z; // "Chunk-relative (x, y) diff --git a/project/handmade.hpp b/project/handmade.hpp index f5fa7a1..ba98719 100644 --- a/project/handmade.hpp +++ b/project/handmade.hpp @@ -149,6 +149,8 @@ struct GameState Player player_1; Player player_2; + + engine::TileMapPos spawn_pos; // PlayerState player_state; // PlayerState player_state_2; diff --git a/project/platform/intrinsics.hpp b/project/platform/intrinsics.hpp index e036cba..583d58f 100644 --- a/project/platform/intrinsics.hpp +++ b/project/platform/intrinsics.hpp @@ -14,6 +14,13 @@ f32 abs( f32 value ) return result; } +inline +s32 sign( s32 value ) +{ + s32 result = value >= 0 ? 1 : -1; + return result; +} + inline f32 sqrt( f32 value ) {