diff --git a/game/game b/game/game index 078461c..df7ac7c 100755 Binary files a/game/game and b/game/game differ diff --git a/game/game.odin b/game/game.odin index cb48a93..f4d1c12 100644 --- a/game/game.odin +++ b/game/game.odin @@ -25,7 +25,7 @@ main :: proc() { rl.SetTargetFPS(60) player = { - position = {CELL_SIZE * 10000, CELL_SIZE * 10000}, + position = {CELL_SIZE * 10, CELL_SIZE * 10}, camera = { zoom = 4, target = {player.position.x + (CELL_SIZE / 2), player.position.y + (CELL_SIZE / 2)}, @@ -37,7 +37,7 @@ main :: proc() { load_tilemap() defer unload_tilemap() - world = create_world("test_world", 23456725245) + world = create_world("test_world", 10172020) save_world(&world) game_loop() @@ -45,8 +45,6 @@ main :: proc() { game_loop :: proc() { - pos_string : string - pos_cstring : cstring for !rl.WindowShouldClose() { @@ -66,13 +64,21 @@ game_loop :: proc() { player_grid_pos_tile := get_world_tile(&world, vec2_to_vec2i(player_grid_pos)) current_chunk := get_chunk_from_world_pos(&world, player_grid_pos) status_string := rl.TextFormat("POS: [%i,%i] : %v | Chunk: [%i,%i] : %v | MODE: %v", int(player_grid_pos.x), int(player_grid_pos.y), player_grid_pos_tile.type, current_chunk.position.x, current_chunk.position.y, get_biome_from_id(current_chunk.biome_id).name, player.mode) + pos_string := rl.TextFormat("Actual pos: %v", player.position) rl.DrawText(status_string, 5, 25, 20, rl.RED) + // Debug: Draw collision check position + target_pos := player_grid_pos + chunk_pos := world_pos_to_chunk_pos(player_grid_pos) + local_pos := get_local_chunk_pos(vec2_to_vec2i(player_grid_pos)) + format_string := rl.TextFormat("Grid: (%.0f,%.0f) Chunk: (%d,%d) Local: (%d,%d)", + player_grid_pos.x, player_grid_pos.y, + chunk_pos.x, chunk_pos.y, + local_pos.x, local_pos.y) + rl.DrawText(format_string, 10, 45, 20, rl.YELLOW) + rl.EndDrawing() } - - delete(pos_string) - delete(pos_cstring) } update :: proc() { diff --git a/game/math.odin b/game/math.odin index 793b52e..433058e 100644 --- a/game/math.odin +++ b/game/math.odin @@ -12,7 +12,7 @@ vec2i_to_vec2 :: proc(v2i:Vec2i) -> [2]f32 { } vec2_to_vec2i :: proc(v2:[2]f32) -> Vec2i { - return {int(v2.x), int(v2.y)} + return {int(math.floor(v2.x)), int(math.floor(v2.y))} } hash_noise :: proc(x, y: int, seed: i64) -> f32 { diff --git a/game/player.odin b/game/player.odin index 708d161..93e8d77 100644 --- a/game/player.odin +++ b/game/player.odin @@ -2,6 +2,7 @@ package game import rl "vendor:raylib" import "core:fmt" +import "core:math" CHUNK_UNLOAD_DISTANCE :: 3 @@ -31,57 +32,42 @@ player_update :: proc(p : ^Player, w: ^World) { handle_player_input(p,w) handle_player_camera(p) - if rl.IsKeyPressed(.SPACE) { - // set_tile(w, bricks_tile, vec2_to_vec2i(get_player_grid_position(p))) - find_desert(w.seed) - generate_biome_map(w.seed, 100, 100) - } + // if rl.IsKeyPressed(.SPACE) { + // // set_tile(w, bricks_tile, vec2_to_vec2i(get_player_grid_position(p))) + // find_desert(w.seed) + // generate_biome_map(w.seed, 100, 100) + // } } @(private="file") player_update_chunks :: proc(p: ^Player, w: ^World) { + // Configurable view distance (in chunks) + VIEW_DISTANCE :: 2 + player_grid_pos := get_player_grid_position(p) current_player_chunk := get_chunk_from_world_pos(w, player_grid_pos) - - directions := [8]Vec2i{ - Vec2i{ 1, 0 }, Vec2i{ -1, 0 }, // Right, Left - Vec2i{ 0, 1 }, Vec2i{ 0, -1 }, // Down, Up - Vec2i{ 1, 1 }, Vec2i{ -1, -1 }, // Bottom-right, Top-left - Vec2i{ 1, -1 }, Vec2i{ -1, 1 }, // Top-right, Bottom-left - } - - // Always ensure the current chunk is loaded - get_chunk(w, current_player_chunk.position) - - // Load adjacent chunks - for dir in directions { - adjacent_pos := Vec2i{ - current_player_chunk.position.x + dir.x, - current_player_chunk.position.y + dir.y + + // Track which chunks should be loaded + chunks_to_keep := make(map[Vec2i]bool) + defer delete(chunks_to_keep) + + // Load chunks in a square around the player's current chunk + for y := -VIEW_DISTANCE; y <= VIEW_DISTANCE; y += 1 { + for x := -VIEW_DISTANCE; x <= VIEW_DISTANCE; x += 1 { + chunk_pos := Vec2i{ + current_player_chunk.position.x + x, + current_player_chunk.position.y + y, + } + + // Load the chunk and mark it to keep + get_chunk(w, chunk_pos) + chunks_to_keep[chunk_pos] = true } - - get_chunk(w, adjacent_pos) } - - // Unload non-adjacent chunks + + // Unload chunks outside the view distance for chunk_pos in w.chunks { - if chunk_pos == current_player_chunk.position { - continue - } - - is_adjacent := false - for dir in directions { - check_pos := Vec2i{ - current_player_chunk.position.x + dir.x, - current_player_chunk.position.y + dir.y - } - if chunk_pos == check_pos { - is_adjacent = true - break - } - } - - if !is_adjacent { + if !chunks_to_keep[chunk_pos] { unload_chunk(chunk_pos, w) } } @@ -91,7 +77,7 @@ player_update_chunks :: proc(p: ^Player, w: ^World) { handle_player_input :: proc(p:^Player, w:^World) { // Movement - target_pos := get_player_grid_position(p) + dt := rl.GetFrameTime() move_delay : f32 = 0.2 if p.move_timer > 0 { @@ -99,9 +85,10 @@ handle_player_input :: proc(p:^Player, w:^World) { } if p.move_timer <= 0 { + current_pos := get_player_grid_position(p) if rl.IsKeyDown(.D) { - target_pos.x += 1 - if !will_collide(w, target_pos) { + target_pos := rl.Vector2{current_pos.x + 1, current_pos.y} + if !will_collide(.RIGHT, p, w) { player.position.x += CELL_SIZE p.move_timer = move_delay player_update_chunks(p,w) @@ -109,8 +96,8 @@ handle_player_input :: proc(p:^Player, w:^World) { } if rl.IsKeyDown(.A) { - target_pos.x -= 1 - if !will_collide(w, target_pos) { + target_pos := rl.Vector2{current_pos.x - 1, current_pos.y} + if !will_collide(.LEFT, p, w) { player.position.x -= CELL_SIZE p.move_timer = move_delay player_update_chunks(p,w) @@ -118,8 +105,8 @@ handle_player_input :: proc(p:^Player, w:^World) { } if rl.IsKeyDown(.W) { - target_pos.y -= 1 - if !will_collide(w, target_pos) { + target_pos := rl.Vector2{current_pos.x, current_pos.y - 1} + if !will_collide(.UP, p, w) { player.position.y -= CELL_SIZE p.move_timer = move_delay player_update_chunks(p,w) @@ -127,8 +114,8 @@ handle_player_input :: proc(p:^Player, w:^World) { } if rl.IsKeyDown(.S) { - target_pos.y += 1 - if !will_collide(w, target_pos) { + target_pos := rl.Vector2{current_pos.x, current_pos.y + 1} + if !will_collide(.DOWN, p, w) { p.move_timer = move_delay player.position.y += CELL_SIZE player_update_chunks(p,w) @@ -194,29 +181,50 @@ get_tile_in_direction :: proc(direction:InteractDirection, p:^Player, w:^World) } get_player_grid_position :: proc(player:^Player) -> rl.Vector2 { - grid_pos_x := player.position.x / CELL_SIZE - grid_pos_y := player.position.y / CELL_SIZE + grid_pos_x := math.floor(player.position.x / CELL_SIZE) + grid_pos_y := math.floor(player.position.y / CELL_SIZE) return {grid_pos_x, grid_pos_y} } draw_player :: proc(player:^Player) { draw_tile({25,0}, player.position, {30,100,120,255}) + + // Debug: Draw player's grid cell + // player_grid_pos := get_player_grid_position(player) + // world_pos_x := player_grid_pos.x * CELL_SIZE + // world_pos_y := player_grid_pos.y * CELL_SIZE + // rl.DrawRectangleLines( + // i32(world_pos_x), + // i32(world_pos_y), + // i32(CELL_SIZE), + // i32(CELL_SIZE), + // rl.RED + // ) + + } +will_collide :: proc(direction:InteractDirection, p:^Player, w:^World) -> bool { + tile, pos := get_tile_in_direction(direction, p, w) -will_collide :: proc(w:^World, pos:rl.Vector2) -> bool { - world_grid_pos := vec2_to_vec2i(pos) - chunk_pos := world_pos_to_chunk_pos(pos) - local_pos := get_local_chunk_pos(world_grid_pos) - - chunk := get_chunk(w, chunk_pos) - tile := get_chunk_tile(chunk, local_pos) - - #partial switch tile.type { - case .SOLID: - return true - } + if tile.type == .SOLID { return true } return false } + +// will_collide :: proc(w:^World, pos:rl.Vector2) -> bool { +// world_grid_pos := vec2_to_vec2i(pos) +// chunk_pos := world_pos_to_chunk_pos(pos) +// local_pos := get_local_chunk_pos(world_grid_pos) + +// chunk := get_chunk(w, chunk_pos) +// tile := get_chunk_tile(chunk, local_pos) + +// #partial switch tile.type { +// case .SOLID: +// return true +// } + +// return false +// } diff --git a/game/world.odin b/game/world.odin index d4d1ece..3744f70 100644 --- a/game/world.odin +++ b/game/world.odin @@ -5,6 +5,7 @@ import "core:fmt" import "core:os" import "core:path/filepath" import "core:mem" +import "core:math" CELL_SIZE :: 16 CHUNK_SIZE :: 32 @@ -173,24 +174,37 @@ get_chunk_from_world_pos :: proc(w:^World, pos:rl.Vector2) -> ^Chunk { } world_pos_to_chunk_pos :: proc(pos:rl.Vector2) -> Vec2i { - chunk_pos := vec2_to_vec2i({pos.x / CHUNK_SIZE, pos.y / CHUNK_SIZE}) - return chunk_pos + + x := int(math.floor(pos.x / CHUNK_SIZE)) + y := int(math.floor(pos.y / CHUNK_SIZE)) + return Vec2i{x,y} } get_local_chunk_pos :: proc(pos:Vec2i) -> Vec2i { - return Vec2i { - (pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE, - (pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE, - } + x := (pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE + y := (pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE + + return Vec2i{x,y} } get_world_tile :: proc(w:^World, pos:Vec2i) -> ^Tile { - chunk_pos := world_pos_to_chunk_pos(vec2i_to_vec2(pos)) - local_pos := get_local_chunk_pos(pos) + chunk_x := int(math.floor(f32(pos.x) / f32(CHUNK_SIZE))) + chunk_y := int(math.floor(f32(pos.y) / f32(CHUNK_SIZE))) + chunk_pos := Vec2i{chunk_x, chunk_y} + + local_x := (pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE + local_y := (pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE + local_pos := Vec2i{local_x, local_y} chunk := get_chunk(w, chunk_pos) - return get_chunk_tile(chunk, local_pos) + + // chunk_pos := world_pos_to_chunk_pos(vec2i_to_vec2(pos)) + // local_pos := get_local_chunk_pos(pos) + // + // chunk := get_chunk(w, chunk_pos) + + // return get_chunk_tile(chunk, local_pos) } get_chunk_tile :: proc(c:^Chunk, pos:Vec2i) -> ^Tile {