package game import "core:fmt" import rl "vendor:raylib" Player_State :: enum { IDLE, WALK, ATTACK } Player :: struct { position: 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.position = {260, 260} player.speed = 180 player.accel = 720 player.friction = 640 player.state = .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 } get_player_center :: proc(player: ^Player) -> rl.Vector2 { return rl.Vector2{ player.position.x + TILE_SIZE / 2, player.position.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, enemies: ^[MAX_ENEMIES]Enemy, active_enemies: int ) { moving := false dt := rl.GetFrameTime() input_dir := rl.Vector2{0,0} if rl.IsKeyDown(.W) || rl.IsKeyDown(.UP) { moving = true; input_dir.y -= 1 } if rl.IsKeyDown(.S) || rl.IsKeyDown(.DOWN) { moving = true; input_dir.y += 1 } if rl.IsKeyDown(.A) || rl.IsKeyDown(.LEFT) { moving = true; input_dir.x -= 1; player.flipped = true } if rl.IsKeyDown(.D) || rl.IsKeyDown(.RIGHT) { moving = true; input_dir.x += 1; player.flipped = false } GAMEPAD :: 1 if rl.IsGamepadAvailable(GAMEPAD) { rl.HideCursor() // D-pad (buttons) — same digital feel as WASD if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_UP) { moving = true; input_dir.y -= 1 } if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_DOWN) { moving = true; input_dir.y += 1 } if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_LEFT) { moving = true; input_dir.x -= 1; player.flipped = true } if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_RIGHT) { moving = true; input_dir.x += 1; player.flipped = false } // Left analog stick, with a deadzone stick_x := rl.GetGamepadAxisMovement(GAMEPAD, .LEFT_X) stick_y := rl.GetGamepadAxisMovement(GAMEPAD, .LEFT_Y) DEADZONE :: 0.25 if abs(stick_x) > DEADZONE { moving = true input_dir.x += stick_x player.flipped = stick_x < 0 } if abs(stick_y) > DEADZONE { moving = true input_dir.y += stick_y } } 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.position.x + new_position.x, player.position.y} if !check_map_collision(get_player_collider(player, new_x_pos), game_map) && !check_enemy_collision(get_player_collider(player, new_x_pos), active_enemies, enemies) { player.position.x = new_x_pos.x } else { player.velocity.x = 0 } new_y_pos := rl.Vector2{player.position.x, player.position.y + new_position.y} if !check_map_collision(get_player_collider(player, new_y_pos), game_map) && !check_enemy_collision(get_player_collider(player, new_y_pos), active_enemies, enemies) { player.position.y = new_y_pos.y } else { player.velocity.y = 0 } // @TESTING if rl.IsMouseButtonPressed(.LEFT) { 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.animation, &assets.clips[player.state]) animation_update(&player.animation, dt) } draw_player :: proc(player: ^Player) { clip := player.animation.clip src_rect := animation_frame_rect(&player.animation) if player.flipped { src_rect.width = -src_rect.width } dst_rect := rl.Rectangle{ x = player.position.x, y = player.position.y, width = f32(clip.frame_width), height = f32(clip.frame_height), } rl.DrawTexturePro(clip.texture, src_rect, dst_rect, rl.Vector2{}, 0, rl.WHITE) }