Add keyboard play: arrows/WASD/hjkl focus, Enter/Space flips
Focus ring appears on the first key press and hides when the mouse moves. Enter also triggers Play Again on the win panel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8214fda8f6
commit
685182b25d
4 files changed
+74
-9
No files matched your search
+42
-2
@@ -56,6 +56,8 @@ elapsed: f32
|
||||
resolve_timer: f32
|
||||
win_t: f32 // fades in the win panel
|
||||
restart_requested: bool
|
||||
focus: int // card selected with the keyboard
|
||||
keyboard_active: bool // show the focus ring (hidden again when the mouse moves)
|
||||
|
||||
// Deals a new game and renders the card faces. Needs the window to exist.
|
||||
start :: proc(deck_id: decks.Deck_Id, game_difficulty: Difficulty) {
|
||||
@@ -112,6 +114,7 @@ deal :: proc(deck_id: decks.Deck_Id, game_difficulty: Difficulty) {
|
||||
resolve_timer = 0
|
||||
win_t = 0
|
||||
restart_requested = false
|
||||
focus = 0
|
||||
}
|
||||
|
||||
active_cards :: proc() -> []card.Card {
|
||||
@@ -146,6 +149,42 @@ select_card :: proc(i: int) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Moves the keyboard focus within the grid, clamped at the edges
|
||||
move_focus :: proc(dx, dy: int) {
|
||||
col := clamp(focus % layout.cols + dx, 0, layout.cols - 1)
|
||||
row := clamp(focus / layout.cols + dy, 0, layout.rows - 1)
|
||||
focus = row * layout.cols + col
|
||||
}
|
||||
|
||||
@(private)
|
||||
key_pressed :: proc(keys: ..raylib.KeyboardKey) -> bool {
|
||||
for key in keys {
|
||||
if raylib.IsKeyPressed(key) || raylib.IsKeyPressedRepeat(key) { return true }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Arrows, WASD or vim keys move the focus; Enter or Space flips the focused card
|
||||
@(private)
|
||||
handle_keyboard :: proc() {
|
||||
if raylib.GetMouseDelta() != {} { keyboard_active = false }
|
||||
|
||||
dx, dy := 0, 0
|
||||
if key_pressed(.LEFT, .A, .H) { dx -= 1 }
|
||||
if key_pressed(.RIGHT, .D, .L) { dx += 1 }
|
||||
if key_pressed(.UP, .W, .K) { dy -= 1 }
|
||||
if key_pressed(.DOWN, .S, .J) { dy += 1 }
|
||||
if dx != 0 || dy != 0 {
|
||||
// The first key press only reveals the focus ring
|
||||
if keyboard_active { move_focus(dx, dy) }
|
||||
keyboard_active = true
|
||||
}
|
||||
if raylib.IsKeyPressed(.ENTER) || raylib.IsKeyPressed(.SPACE) {
|
||||
keyboard_active = true
|
||||
select_card(focus)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
resolve :: proc() {
|
||||
a, b := &cards[first], &cards[second]
|
||||
@@ -180,6 +219,7 @@ update :: proc(dt: f32) {
|
||||
}
|
||||
|
||||
for &c in active_cards() { card.update(&c, dt) }
|
||||
if state != .OVER { handle_keyboard() }
|
||||
|
||||
switch state {
|
||||
case .WAITING, .FIRST:
|
||||
@@ -221,7 +261,7 @@ draw :: proc() -> themes.Screen {
|
||||
}
|
||||
|
||||
for &c, i in active_cards() {
|
||||
card.draw(&c, theme, can_pick(i))
|
||||
card.draw(&c, theme, can_pick(i), focused = keyboard_active && i == focus && state != .OVER)
|
||||
}
|
||||
|
||||
if state == .OVER {
|
||||
@@ -256,7 +296,7 @@ draw_win_panel :: proc() -> Maybe(themes.Screen) {
|
||||
if win_t < 1 { return nil }
|
||||
button_w: f32 = 200
|
||||
button_y := panel.y + panel_h - 100
|
||||
if ui.button({cx - button_w - 10, button_y, button_w, 60}, "Play Again", theme.primary) {
|
||||
if ui.button({cx - button_w - 10, button_y, button_w, 60}, "Play Again", theme.primary, hotkey = .ENTER) {
|
||||
restart_requested = true
|
||||
}
|
||||
if ui.button({cx + 10, button_y, button_w, 60}, "Menu", theme.ink) {
|
||||
|
||||
Reference in new issue
Block a user