Files
raylib_reference/src/player.odin
T

169 lines
4.9 KiB
Odin

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)
}