Added basic event listener. Game state and player use events.
This commit is contained in:
@@ -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)
|
||||||
|
// }
|
||||||
+40
-12
@@ -1,14 +1,21 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import "core:fmt"
|
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
Game_State :: enum {
|
||||||
|
MENU,
|
||||||
|
PAUSED,
|
||||||
|
RUNNING,
|
||||||
|
GAME_OVER,
|
||||||
|
}
|
||||||
|
|
||||||
Game :: struct {
|
Game :: struct {
|
||||||
// debug info
|
// debug info
|
||||||
debug: Debug,
|
debug: Debug,
|
||||||
|
|
||||||
// Game info
|
// Game info
|
||||||
|
state: Game_State,
|
||||||
world: rl.RenderTexture2D,
|
world: rl.RenderTexture2D,
|
||||||
camera: rl.Camera2D,
|
camera: rl.Camera2D,
|
||||||
assets: Asset_Manager,
|
assets: Asset_Manager,
|
||||||
@@ -21,10 +28,22 @@ Game :: struct {
|
|||||||
enenmy_spawn_timer: Timer
|
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!
|
// awesome odin lets me load this at compile time!
|
||||||
gamepad_compat := #load("../gamecontrollerdb.txt", string)
|
gamepad_compat := #load("../gamecontrollerdb.txt", string)
|
||||||
|
|
||||||
game_init :: proc() -> Game {
|
game_init :: proc() -> Game {
|
||||||
|
|
||||||
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
|
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
|
||||||
rl.SetTargetFPS(60)
|
rl.SetTargetFPS(60)
|
||||||
|
|
||||||
@@ -32,8 +51,11 @@ game_init :: proc() -> Game {
|
|||||||
defer delete(gamepad_cstr)
|
defer delete(gamepad_cstr)
|
||||||
rl.SetGamepadMappings(gamepad_cstr)
|
rl.SetGamepadMappings(gamepad_cstr)
|
||||||
|
|
||||||
|
rl.SetExitKey(.KEY_NULL)
|
||||||
|
|
||||||
// ! game setup
|
// ! game setup
|
||||||
game := Game{}
|
game := Game{}
|
||||||
|
game.state = .RUNNING
|
||||||
game.assets = asset_manager_init()
|
game.assets = asset_manager_init()
|
||||||
game.player = player_init(&game.assets.player)
|
game.player = player_init(&game.assets.player)
|
||||||
game.camera = camera_init(&game.player, 1)
|
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)
|
game.current_map.player_grid_pos = world_to_grid(game.player.position)
|
||||||
|
|
||||||
// ! init timers
|
// ! init timers
|
||||||
game.enenmy_spawn_timer = init_timer(0.1, true)
|
game.enenmy_spawn_timer = init_timer(0.5, true)
|
||||||
|
|
||||||
// flow field on boot
|
// flow field on boot
|
||||||
compute_flow_field(&game.current_map, game.player.position)
|
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_should_run :: proc(game: ^Game) -> bool { return !rl.WindowShouldClose() }
|
||||||
|
|
||||||
game_update :: proc(game: ^Game) {
|
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)
|
if actions.pause_pressed {
|
||||||
update_player_flow_field(&game.player, &game.current_map)
|
game.state = game.state == .PAUSED ? .RUNNING : .PAUSED
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
update_enemies(&game.enemies, &game.assets.enemy, game.enemy_count, dt)
|
|
||||||
|
|
||||||
// @ DEBUG
|
if game.state != .PAUSED {
|
||||||
debug_camera_update(&game.debug)
|
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) {
|
game_draw :: proc(game: ^Game) {
|
||||||
@@ -126,3 +153,4 @@ game_close :: proc(game: ^Game) {
|
|||||||
rl.UnloadRenderTexture(game.world)
|
rl.UnloadRenderTexture(game.world)
|
||||||
rl.CloseWindow()
|
rl.CloseWindow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-43
@@ -1,9 +1,7 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
import "core:fmt"
|
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
Player_State :: enum { IDLE, WALK, ATTACK }
|
Player_State :: enum { IDLE, WALK, ATTACK }
|
||||||
|
|
||||||
Player :: struct {
|
Player :: struct {
|
||||||
@@ -30,9 +28,9 @@ player_init :: proc(assets: ^Player_Assets) -> Player {
|
|||||||
player.accel = 720
|
player.accel = 720
|
||||||
player.friction = 640
|
player.friction = 640
|
||||||
player.state = .IDLE
|
player.state = .IDLE
|
||||||
player.collider_offset = rl.Vector2{8, 15}
|
player.collider_offset = rl.Vector2{10, 14}
|
||||||
player.collider_w = 16
|
player.collider_w = 12
|
||||||
player.collider_h = 10
|
player.collider_h = 18
|
||||||
animation_play(&player.animation, &assets.clips[.IDLE])
|
animation_play(&player.animation, &assets.clips[.IDLE])
|
||||||
|
|
||||||
return player
|
return player
|
||||||
@@ -55,52 +53,22 @@ get_player_collider :: proc(player: ^Player, pos: rl.Vector2) -> rl.Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_player :: proc(
|
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,
|
game_map: Game_Map, enemies: ^[MAX_ENEMIES]Enemy, active_enemies: int,
|
||||||
dt: f32
|
dt: f32
|
||||||
) {
|
) {
|
||||||
moving := false
|
input_dir := actions.move_dir
|
||||||
input_dir := rl.Vector2{0,0}
|
moving := input_dir != rl.Vector2{0, 0}
|
||||||
|
|
||||||
if rl.IsKeyDown(.W) || rl.IsKeyDown(.UP) { moving = true; input_dir.y -= 1 }
|
if input_dir.x < 0 do player.flipped = true
|
||||||
if rl.IsKeyDown(.S) || rl.IsKeyDown(.DOWN) { moving = true; input_dir.y += 1 }
|
if input_dir.x > 0 do player.flipped = false
|
||||||
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
|
is_attacking := player.state == .ATTACK && !player.animation.finished
|
||||||
if rl.IsGamepadAvailable(GAMEPAD) {
|
attack_pressed := actions.attack_pressed && !is_attacking
|
||||||
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)
|
// Move velocity toward target (accelerate) or toward zero (friction)
|
||||||
target_velocity := input_dir * player.speed
|
target_velocity := input_dir * player.speed
|
||||||
if has_input {
|
if moving {
|
||||||
player.velocity = rl.Vector2MoveTowards(player.velocity, target_velocity, player.accel * dt)
|
player.velocity = rl.Vector2MoveTowards(player.velocity, target_velocity, player.accel * dt)
|
||||||
} else {
|
} else {
|
||||||
player.velocity = rl.Vector2MoveTowards(player.velocity, rl.Vector2{0, 0}, player.friction * dt)
|
player.velocity = rl.Vector2MoveTowards(player.velocity, rl.Vector2{0, 0}, player.friction * dt)
|
||||||
|
|||||||
Reference in New Issue
Block a user