Implement automatic Pac-Man movement with queued direction turning
Pac-Man now moves automatically in its current direction every pacman-speed-ms (200ms). Arrow keys queue a desired turn direction instead of moving directly. Each movement tick: 1. Try the queued direction — if passable, turn and move that way 2. Otherwise keep moving in the current direction 3. Stop only when hitting a wall (no direction change) New internal state: - queued-direction: the direction the player wants to turn next - movement-timer: accumulates delta-time, triggers move at interval New helper: - can-move?: checks if a direction is passable (no wall/locked door) Changed behavior: - key-press! now sets queued-direction instead of calling move-pacman! - update! now drives movement via advance-pacman! on a timer - move-pacman! no longer checks time-up? (advance-pacman! handles it) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,11 @@
|
||||
;; Level ADT ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Contains all game logic: Pac-Man movement, collision detection, coin/key
|
||||
;; pickup, door opening, teleportation, pause, and time management.
|
||||
;; Contains NO graphics code.
|
||||
;; Contains all game logic: automatic Pac-Man movement, collision detection,
|
||||
;; coin/key pickup, door opening, teleportation, pause, and time management.
|
||||
;; Pac-Man moves automatically in its current direction. Arrow keys queue a
|
||||
;; desired turn direction, which is applied at the next movement tick if the
|
||||
;; path is clear. Contains NO graphics code.
|
||||
|
||||
(define-library (pacman-project adt level)
|
||||
(import (scheme base)
|
||||
@@ -29,7 +31,9 @@
|
||||
(key #f)
|
||||
(score (make-score))
|
||||
(timer (make-timer))
|
||||
(paused? #f))
|
||||
(paused? #f)
|
||||
(queued-direction #f)
|
||||
(movement-timer 0))
|
||||
|
||||
;; Initialize key after maze is created.
|
||||
(set! key (make-key maze))
|
||||
@@ -47,6 +51,23 @@
|
||||
((eq? direction 'down) (cons 1 0))
|
||||
(else (cons 0 0))))
|
||||
|
||||
;; can-move? :: symbol -> boolean
|
||||
;; Checks if Pac-Man can move in the given direction (no wall or
|
||||
;; locked door blocking the way).
|
||||
(define (can-move? direction)
|
||||
(let* ((delta (direction->delta direction))
|
||||
(current-pos (pacman 'position))
|
||||
(next-row (+ (current-pos 'row) (car delta)))
|
||||
(next-col (+ (current-pos 'col) (cdr delta))))
|
||||
(cond
|
||||
;; Teleportation tunnels are always passable.
|
||||
((or (< next-col 0) (>= next-col (maze 'cols))) #t)
|
||||
;; Walls block.
|
||||
(((maze 'wall?) next-row next-col) #f)
|
||||
;; Doors block unless the key has been taken.
|
||||
(((maze 'door?) next-row next-col) (key 'taken?))
|
||||
(else #t))))
|
||||
|
||||
;;
|
||||
;; Coin logic
|
||||
;;
|
||||
@@ -88,39 +109,54 @@
|
||||
;;
|
||||
|
||||
;; move-pacman! :: symbol -> /
|
||||
;; Moves Pac-Man in the given direction with all game rules.
|
||||
;; Moves Pac-Man one step in the given direction, handling collisions,
|
||||
;; teleportation, and item pickup.
|
||||
(define (move-pacman! direction)
|
||||
(let* ((delta (direction->delta direction))
|
||||
(delta-row (car delta))
|
||||
(delta-col (cdr delta))
|
||||
(current-pos (pacman 'position))
|
||||
(next-row (+ (current-pos 'row) delta-row))
|
||||
(next-col (+ (current-pos 'col) delta-col)))
|
||||
|
||||
;; Update facing direction for the draw layer.
|
||||
((pacman 'direction!) direction)
|
||||
|
||||
(cond
|
||||
;; Teleportation: outside grid horizontally.
|
||||
((or (< next-col 0) (>= next-col (maze 'cols)))
|
||||
(teleport-horizontal! next-row next-col))
|
||||
|
||||
;; Door: open it if key has been taken.
|
||||
(((maze 'door?) next-row next-col)
|
||||
(when (key 'taken?)
|
||||
((maze 'remove-door!) next-row next-col)))
|
||||
|
||||
;; Normal movement: only if not a wall.
|
||||
(else
|
||||
(when (not ((maze 'wall?) next-row next-col))
|
||||
((pacman 'move!) delta-row delta-col)
|
||||
;; Check what's at the new position.
|
||||
(cond
|
||||
(((maze 'key?) next-row next-col)
|
||||
(pick-up-key! next-row next-col))
|
||||
(((maze 'coin?) next-row next-col)
|
||||
(eat-coin! next-row next-col))))))))
|
||||
|
||||
;; advance-pacman! :: -> /
|
||||
;; Called every movement tick. Tries the queued direction first; if
|
||||
;; that path is blocked, continues in the current direction.
|
||||
(define (advance-pacman!)
|
||||
(when (not ((timer 'time-up?)))
|
||||
(let* ((delta (direction->delta direction))
|
||||
(delta-row (car delta))
|
||||
(delta-col (cdr delta))
|
||||
(current-pos (pacman 'position))
|
||||
(next-row (+ (current-pos 'row) delta-row))
|
||||
(next-col (+ (current-pos 'col) delta-col)))
|
||||
|
||||
;; Update direction for the draw layer.
|
||||
((pacman 'direction!) direction)
|
||||
|
||||
(let ((current-dir (pacman 'direction)))
|
||||
;; Try the queued direction first.
|
||||
(cond
|
||||
;; Teleportation: outside grid horizontally.
|
||||
((or (< next-col 0) (>= next-col (maze 'cols)))
|
||||
(teleport-horizontal! next-row next-col))
|
||||
|
||||
;; Door: only open if key has been taken.
|
||||
(((maze 'door?) next-row next-col)
|
||||
(when (key 'taken?)
|
||||
((maze 'remove-door!) next-row next-col)))
|
||||
|
||||
;; Normal movement: only if not a wall.
|
||||
(else
|
||||
(when (not ((maze 'wall?) next-row next-col))
|
||||
((pacman 'move!) delta-row delta-col)
|
||||
;; Check what's at the new position.
|
||||
(cond
|
||||
(((maze 'key?) next-row next-col)
|
||||
(pick-up-key! next-row next-col))
|
||||
(((maze 'coin?) next-row next-col)
|
||||
(eat-coin! next-row next-col)))))))))
|
||||
((and queued-direction (can-move? queued-direction))
|
||||
(move-pacman! queued-direction)
|
||||
(set! queued-direction #f))
|
||||
;; Otherwise keep moving in the current direction.
|
||||
((can-move? current-dir)
|
||||
(move-pacman! current-dir))))))
|
||||
|
||||
;;
|
||||
;; Pause logic
|
||||
@@ -135,26 +171,31 @@
|
||||
;;
|
||||
|
||||
;; key-press! :: symbol -> /
|
||||
;; Processes a key press.
|
||||
;; Processes a key press. Arrow keys queue a desired direction.
|
||||
(define (key-press! pressed-key)
|
||||
(cond
|
||||
((eq? pressed-key 'escape) (toggle-pause!))
|
||||
((not paused?)
|
||||
(cond
|
||||
((eq? pressed-key 'right) (move-pacman! 'right))
|
||||
((eq? pressed-key 'left) (move-pacman! 'left))
|
||||
((eq? pressed-key 'up) (move-pacman! 'up))
|
||||
((eq? pressed-key 'down) (move-pacman! 'down))))))
|
||||
((eq? pressed-key 'right) (set! queued-direction 'right))
|
||||
((eq? pressed-key 'left) (set! queued-direction 'left))
|
||||
((eq? pressed-key 'up) (set! queued-direction 'up))
|
||||
((eq? pressed-key 'down) (set! queued-direction 'down))))))
|
||||
|
||||
;;
|
||||
;; Update (game loop function)
|
||||
;;
|
||||
|
||||
;; update! :: number -> /
|
||||
;; Called each frame with elapsed milliseconds.
|
||||
;; Called each frame with elapsed milliseconds. Advances the movement
|
||||
;; timer and moves Pac-Man automatically when the interval elapses.
|
||||
(define (update! delta-time)
|
||||
(when (not paused?)
|
||||
((timer 'decrease!) delta-time)))
|
||||
((timer 'decrease!) delta-time)
|
||||
(set! movement-timer (+ movement-timer delta-time))
|
||||
(when (>= movement-timer pacman-speed-ms)
|
||||
(advance-pacman!)
|
||||
(set! movement-timer 0))))
|
||||
|
||||
;;
|
||||
;; Dispatch
|
||||
|
||||
Reference in New Issue
Block a user