From 275975f7fb17a50d1e42470e1706b7a2d66cd65c Mon Sep 17 00:00:00 2001 From: Jason Hilder Date: Mon, 20 Jul 2026 08:09:17 +0200 Subject: [PATCH] Neaten player logic and add collisions. --- src/game.odin | 6 +-- src/player.odin | 110 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/game.odin b/src/game.odin index 70e776e..afc2a02 100644 --- a/src/game.odin +++ b/src/game.odin @@ -19,7 +19,7 @@ game_init :: proc() -> Game { game.assets = asset_manager_init() game.player = player_init(&game.assets.player) - game.camera = camera_init(game.player, 1) + game.camera = camera_init(&game.player, 1) game.world = rl.LoadRenderTexture(GAME_WIDTH, GAME_HEIGHT) game.current_map = map_init() @@ -34,8 +34,8 @@ game_should_run :: proc(game: ^Game) -> bool { } game_update :: proc(game: ^Game) { - update_player(&game.player, &game.assets.player, game.camera) - update_camera(game.player.pos, &game.camera) + update_player(&game.player, &game.assets.player, game.camera, game.current_map) + update_camera(&game.player, &game.camera) // DEBUG debug_camera_update(&game.debug) diff --git a/src/player.odin b/src/player.odin index c12fbfb..e1d7913 100644 --- a/src/player.odin +++ b/src/player.odin @@ -3,78 +3,126 @@ package game import "core:fmt" import rl "vendor:raylib" -Direction :: enum { LEFT, RIGHT } Player_State :: enum { IDLE, WALK, ATTACK } Player :: struct { - pos: rl.Vector2, - direction: Direction, - state: Player_State, - ani_state: AnimationState, + pos: rl.Vector2, + + velocity: rl.Vector2, + speed: f32, // max move speed + accel: f32, // how fast to reach speed + friction: f32, // how fast to stop + + state: Player_State, + animation: AnimationState, + flipped: bool, + + collider_offset: rl.Vector2, + collider_w: f32, + collider_h: f32 } player_init :: proc(assets: ^Player_Assets) -> Player { player := Player{} - player.pos = {320, 320} + player.pos = {39, 39} + player.speed = 100 + player.accel = 600 + player.friction = 500 player.state = .IDLE - animation_play(&player.ani_state, &assets.clips[.IDLE]) + player.collider_offset = rl.Vector2{8, 15} + player.collider_w = 16 + player.collider_h = 10 + animation_play(&player.animation, &assets.clips[.IDLE]) return player } -update_player :: proc(player: ^Player, assets: ^Player_Assets, camera: rl.Camera2D) { +get_player_center :: proc(player: ^Player) -> rl.Vector2 { + return rl.Vector2{ + player.pos.x + TILE_SIZE / 2, + player.pos.y + TILE_SIZE / 2, + } +} + +get_player_collider :: proc(player: ^Player, pos: rl.Vector2) -> rl.Rectangle { + return rl.Rectangle{ + (pos.x + player.collider_offset.x), + pos.y + player.collider_offset.y, + player.collider_w, + player.collider_h, + } +} + +update_player :: proc(player: ^Player, assets: ^Player_Assets, camera: rl.Camera2D, game_map: Game_Map) { moving := false dt := rl.GetFrameTime() + input_dir := rl.Vector2{0,0} - if rl.IsKeyDown(.W) { player.pos.y -= PLAYER_SPEED * dt; moving = true } - if rl.IsKeyDown(.S) { player.pos.y += PLAYER_SPEED * dt; moving = true } + if rl.IsKeyDown(.W) { moving = true; input_dir.y -=1; } + if rl.IsKeyDown(.S) { moving = true; input_dir.y +=1; } + if rl.IsKeyDown(.A) { moving = true; input_dir.x -=1; player.flipped = true } + if rl.IsKeyDown(.D) { moving = true; input_dir.x +=1; player.flipped = false } - if rl.IsKeyDown(.A) { - player.pos.x -= PLAYER_SPEED * dt - player.direction = .LEFT - moving = true - } - if rl.IsKeyDown(.D) { - player.pos.x += PLAYER_SPEED * dt - player.direction = .RIGHT - moving = true + has_input := input_dir.x != 0 || input_dir.y != 0 + if has_input { + input_dir = rl.Vector2Normalize(input_dir) } + // Move velocity toward target (accelerate) or toward zero (friction) + target_velocity := input_dir * player.speed + if has_input { + player.velocity = rl.Vector2MoveTowards(player.velocity, target_velocity, player.accel * dt) + } else { + player.velocity = rl.Vector2MoveTowards(player.velocity, rl.Vector2{0, 0}, player.friction * dt) + } + + // Check for collisions + new_position := player.velocity * dt + new_x_pos := rl.Vector2{player.pos.x + new_position.x, player.pos.y} + if !check_map_collision(get_player_collider(player, new_x_pos), game_map) { + player.pos.x = new_x_pos.x + } else { + player.velocity.x = 0 + } + + new_y_pos := rl.Vector2{player.pos.x, player.pos.y + new_position.y} + if !check_map_collision(get_player_collider(player, new_y_pos), game_map) { + player.pos.y = new_y_pos.y + } else { + player.velocity.y = 0 + } + + // TESTING if rl.IsMouseButtonPressed(.LEFT) { - // TESTING mouse_pos := rl.GetMousePosition() screen_space := window_to_screen(mouse_pos) x := screen_to_world(screen_space, camera) fmt.printf("Mouse pos -> world pos: %v\n", x) - v := world_to_screen(x, camera) fmt.printf("world pos -> screen pos: %v\n", v) - y := world_to_grid(x) fmt.printf("Mouse pos -> grid coord: %v\n", y) - z := grid_to_world(y[0], y[1]) fmt.printf("grid pos -> world pos: %v\n", z) } player.state = moving ? .WALK : .IDLE - - animation_play(&player.ani_state, &assets.clips[player.state]) - animation_update(&player.ani_state, dt) + animation_play(&player.animation, &assets.clips[player.state]) + animation_update(&player.animation, dt) } draw_player :: proc(player: ^Player) { - clip := player.ani_state.clip - src_rect := animation_frame_rect(&player.ani_state) + clip := player.animation.clip + src_rect := animation_frame_rect(&player.animation) - if player.direction == .LEFT { + if player.flipped { src_rect.width = -src_rect.width } dst_rect := rl.Rectangle{ - x = player.pos.x - f32(clip.frame_width) / 2, - y = player.pos.y - f32(clip.frame_height) / 2, + x = player.pos.x, + y = player.pos.y, width = f32(clip.frame_width), height = f32(clip.frame_height), }