odin-raylib-game/game/player.odin
2025-03-01 23:10:22 -06:00

223 lines
6.0 KiB
Odin

package game
import rl "vendor:raylib"
import "core:fmt"
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) {
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
}
get_chunk(w, adjacent_pos)
}
// Unload non-adjacent chunks
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 {
unload_chunk(chunk_pos, w)
}
}
}
@(private="file")
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 {
p.move_timer -= dt
}
if p.move_timer <= 0 {
if rl.IsKeyDown(.D) {
target_pos.x += 1
if !will_collide(w, target_pos) {
player.position.x += CELL_SIZE
p.move_timer = move_delay
player_update_chunks(p,w)
}
}
if rl.IsKeyDown(.A) {
target_pos.x -= 1
if !will_collide(w, target_pos) {
player.position.x -= CELL_SIZE
p.move_timer = move_delay
player_update_chunks(p,w)
}
}
if rl.IsKeyDown(.W) {
target_pos.y -= 1
if !will_collide(w, target_pos) {
player.position.y -= CELL_SIZE
p.move_timer = move_delay
player_update_chunks(p,w)
}
}
if rl.IsKeyDown(.S) {
target_pos.y += 1
if !will_collide(w, target_pos) {
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 := player.position.x / CELL_SIZE
grid_pos_y := 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})
}
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
}