package game import rl "vendor:raylib" import "core:fmt" import "core:math" CHUNK_UNLOAD_DISTANCE :: 3 Player :: struct { position : rl.Vector2, move_timer: f32, mode: InteractMode, camera: rl.Camera2D, } InteractMode :: enum { INTERACT, ATTACK, STEAL, } @(private="file") handle_player_camera :: proc(p:^Player) { p.camera.target = {p.position.x + (CELL_SIZE / 2), p.position.y + (CELL_SIZE / 2)} if rl.IsWindowResized() { p.camera.offset = {f32(rl.GetScreenWidth()) / 2, f32(rl.GetScreenHeight()) / 2} } } 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) // } } @(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) // 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 } } // Unload chunks outside the view distance for chunk_pos in w.chunks { if !chunks_to_keep[chunk_pos] { unload_chunk(chunk_pos, w) } } } @(private="file") handle_player_input :: proc(p:^Player, w:^World) { // Movement dt := rl.GetFrameTime() move_delay : f32 = 0.2 if p.move_timer > 0 { p.move_timer -= dt } if p.move_timer <= 0 { current_pos := get_player_grid_position(p) if rl.IsKeyDown(.D) { 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) } } if rl.IsKeyDown(.A) { 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) } } if rl.IsKeyDown(.W) { 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) } } if rl.IsKeyDown(.S) { 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) } } // Interactions if rl.IsKeyPressed(.UP) { if p.mode == .INTERACT { handle_interact(.UP, p, w) } if p.mode == .ATTACK { handle_attack(.UP, p, w) } } if rl.IsKeyPressed(.DOWN) { if p.mode == .INTERACT { handle_interact(.DOWN, p, w) } if p.mode == .ATTACK { handle_attack(.DOWN, p, w) } } if rl.IsKeyPressed(.LEFT) { if p.mode == .INTERACT { handle_interact(.LEFT, p, w) } if p.mode == .ATTACK { handle_attack(.LEFT, p, w) } } if rl.IsKeyPressed(.RIGHT) { if p.mode == .INTERACT { handle_interact(.RIGHT, p, w) } if p.mode == .ATTACK { handle_attack(.RIGHT, p, w) } } if rl.IsKeyPressed(.ONE) { p.mode = .INTERACT } if rl.IsKeyPressed(.TWO) { p.mode = .ATTACK } if rl.IsKeyPressed(.THREE) { p.mode = .STEAL } } } @(private="file") InteractDirection :: enum { UP, DOWN, LEFT, RIGHT } @(private="file") handle_interact :: proc(direction:InteractDirection, p:^Player, w:^World) { tile, pos := get_tile_in_direction(direction, p, w) if tile.interaction == .RESOURCE && tile.resource != .NOTHING { if tile.resource == .TREE { handle_tree_interaction(w, p, pos) } } } @(private="file") handle_attack :: proc(direction:InteractDirection, p:^Player, w:^World) { tile, pos := get_tile_in_direction(direction, p, w) } @(private="file") get_tile_in_direction :: proc(direction:InteractDirection, p:^Player, w:^World) -> (^Tile, Vec2i) { grid_pos := get_player_grid_position(p) if direction == .UP { grid_pos.y -= 1 } if direction == .DOWN { grid_pos.y += 1 } if direction == .LEFT { grid_pos.x -= 1 } if direction == .RIGHT { grid_pos.x += 1 } return get_world_tile(w, vec2_to_vec2i(grid_pos)), vec2_to_vec2i(grid_pos) } get_player_grid_position :: proc(player:^Player) -> rl.Vector2 { 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) 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 // }