From 4c98ca61c5fd60e35d4c8f019e8bbda445fbc060 Mon Sep 17 00:00:00 2001 From: joren Date: Mon, 23 Mar 2026 11:15:46 +0100 Subject: [PATCH] Implement automatic Pac-Man movement with queued direction turning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- pacman-project/adt/level.rkt | 123 +++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 41 deletions(-) diff --git a/pacman-project/adt/level.rkt b/pacman-project/adt/level.rkt index 2904fd8..06b1cb3 100644 --- a/pacman-project/adt/level.rkt +++ b/pacman-project/adt/level.rkt @@ -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