From c1f481dd821864e7c33b1cd601887fb6bb617ba6 Mon Sep 17 00:00:00 2001 From: Jason Hilder Date: Mon, 3 Aug 2026 06:40:54 +0200 Subject: [PATCH] Added basic event listener. Game state and player use events. --- src/events.odin | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ src/game.odin | 52 ++++++++++++++++++++++++++++++---------- src/player.odin | 56 ++++++++++--------------------------------- 3 files changed, 115 insertions(+), 56 deletions(-) create mode 100644 src/events.odin diff --git a/src/events.odin b/src/events.odin new file mode 100644 index 0000000..f23010e --- /dev/null +++ b/src/events.odin @@ -0,0 +1,63 @@ +package game + +import "core:fmt" +import rl "vendor:raylib" + +game_poll_events :: proc() -> Actions { + actions := Actions{} + + // @TODO: Escape key is weird, is it wayland/x11 or linux or something else?? + actions.pause_pressed = rl.IsKeyPressed(.TAB) + + input_dir := rl.Vector2{0,0} + + if rl.IsKeyDown(.W) || rl.IsKeyDown(.UP) { input_dir.y -= 1 } + if rl.IsKeyDown(.S) || rl.IsKeyDown(.DOWN) { input_dir.y += 1 } + if rl.IsKeyDown(.A) || rl.IsKeyDown(.LEFT) { input_dir.x -= 1 } + if rl.IsKeyDown(.D) || rl.IsKeyDown(.RIGHT) { input_dir.x += 1 } + + // @TODO gamepad merging would go here too, same as before + + GAMEPAD :: 1 + if rl.IsGamepadAvailable(GAMEPAD) { + rl.HideCursor() + + // D-pad (buttons) — same digital feel as WASD + if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_UP) { input_dir.y -= 1 } + if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_DOWN) { input_dir.y += 1 } + if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_LEFT) { input_dir.x -= 1 } + if rl.IsGamepadButtonDown(GAMEPAD, .LEFT_FACE_RIGHT) { input_dir.x += 1 } + + // 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 do input_dir.x += stick_x + if abs(stick_y) > DEADZONE do input_dir.y += stick_y + } + + if input_dir.x != 0 || input_dir.y != 0 { + input_dir = rl.Vector2Normalize(input_dir) + } + actions.move_dir = input_dir + + actions.attack_pressed = rl.IsMouseButtonPressed(.LEFT) + + return actions +} + +// @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) +// } diff --git a/src/game.odin b/src/game.odin index d5982de..01f18b6 100644 --- a/src/game.odin +++ b/src/game.odin @@ -1,14 +1,21 @@ package game -import "core:fmt" import "core:strings" import rl "vendor:raylib" +Game_State :: enum { + MENU, + PAUSED, + RUNNING, + GAME_OVER, +} + Game :: struct { // debug info debug: Debug, // Game info + state: Game_State, world: rl.RenderTexture2D, camera: rl.Camera2D, assets: Asset_Manager, @@ -21,10 +28,22 @@ Game :: struct { enenmy_spawn_timer: Timer } +Actions :: struct { + // normalized and merged from keyboard + controller + move_dir: rl.Vector2, + + attack_pressed: bool, + dash_pressed: bool, + interact_press: bool, + + pause_pressed: bool +} + // awesome odin lets me load this at compile time! gamepad_compat := #load("../gamecontrollerdb.txt", string) game_init :: proc() -> Game { + rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE) rl.SetTargetFPS(60) @@ -32,8 +51,11 @@ game_init :: proc() -> Game { defer delete(gamepad_cstr) rl.SetGamepadMappings(gamepad_cstr) + rl.SetExitKey(.KEY_NULL) + // ! game setup game := Game{} + game.state = .RUNNING game.assets = asset_manager_init() game.player = player_init(&game.assets.player) game.camera = camera_init(&game.player, 1) @@ -42,7 +64,7 @@ game_init :: proc() -> Game { game.current_map.player_grid_pos = world_to_grid(game.player.position) // ! init timers - game.enenmy_spawn_timer = init_timer(0.1, true) + game.enenmy_spawn_timer = init_timer(0.5, true) // flow field on boot compute_flow_field(&game.current_map, game.player.position) @@ -57,19 +79,24 @@ game_init :: proc() -> Game { game_should_run :: proc(game: ^Game) -> bool { return !rl.WindowShouldClose() } game_update :: proc(game: ^Game) { - dt := rl.GetFrameTime() + dt := rl.GetFrameTime() + actions := game_poll_events() - update_player(&game.player, &game.assets.player, game.camera, game.current_map, &game.enemies, game.enemy_count, dt) - update_player_flow_field(&game.player, &game.current_map) - update_camera(&game.player, &game.camera, game.current_map.width_px, game.current_map.height_px) - - if update_timer(&game.enenmy_spawn_timer, dt) { - spawn_enemy(&game.enemies, &game.assets.enemy, &game.enemy_count, game.current_map) + if actions.pause_pressed { + game.state = game.state == .PAUSED ? .RUNNING : .PAUSED } - update_enemies(&game.enemies, &game.assets.enemy, game.enemy_count, dt) - // @ DEBUG - debug_camera_update(&game.debug) + if game.state != .PAUSED { + update_player(&game.player, actions, &game.assets.player, game.camera, game.current_map, &game.enemies, game.enemy_count, dt) + update_player_flow_field(&game.player, &game.current_map) + update_camera(&game.player, &game.camera, game.current_map.width_px, game.current_map.height_px) + + if update_timer(&game.enenmy_spawn_timer, dt) do spawn_enemy(&game.enemies, &game.assets.enemy, &game.enemy_count, game.current_map) + update_enemies(&game.enemies, &game.assets.enemy, game.enemy_count, game.current_map, dt) + } + + // @ DEBUG + debug_camera_update(&game.debug) } game_draw :: proc(game: ^Game) { @@ -126,3 +153,4 @@ game_close :: proc(game: ^Game) { rl.UnloadRenderTexture(game.world) rl.CloseWindow() } + diff --git a/src/player.odin b/src/player.odin index e23753d..a92c499 100644 --- a/src/player.odin +++ b/src/player.odin @@ -1,9 +1,7 @@ package game -import "core:fmt" import rl "vendor:raylib" - Player_State :: enum { IDLE, WALK, ATTACK } Player :: struct { @@ -30,9 +28,9 @@ player_init :: proc(assets: ^Player_Assets) -> Player { player.accel = 720 player.friction = 640 player.state = .IDLE - player.collider_offset = rl.Vector2{8, 15} - player.collider_w = 16 - player.collider_h = 10 + player.collider_offset = rl.Vector2{10, 14} + player.collider_w = 12 + player.collider_h = 18 animation_play(&player.animation, &assets.clips[.IDLE]) return player @@ -55,52 +53,22 @@ get_player_collider :: proc(player: ^Player, pos: rl.Vector2) -> rl.Rectangle { } update_player :: proc( - player: ^Player, assets: ^Player_Assets, camera: rl.Camera2D, + player: ^Player, actions: Actions, assets: ^Player_Assets, camera: rl.Camera2D, game_map: Game_Map, enemies: ^[MAX_ENEMIES]Enemy, active_enemies: int, dt: f32 ) { - moving := false - input_dir := rl.Vector2{0,0} + input_dir := actions.move_dir + moving := input_dir != rl.Vector2{0, 0} + + if input_dir.x < 0 do player.flipped = true + if input_dir.x > 0 do player.flipped = false - 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) - } + is_attacking := player.state == .ATTACK && !player.animation.finished + attack_pressed := actions.attack_pressed && !is_attacking // Move velocity toward target (accelerate) or toward zero (friction) target_velocity := input_dir * player.speed - if has_input { + if moving { 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)