Compare commits
3 Commits
optimize/d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91b548e0bf | ||
|
|
b18aa49e8b | ||
|
|
3f12a740da |
@@ -23,23 +23,38 @@
|
|||||||
;; make-draw :: number, number -> draw
|
;; make-draw :: number, number -> draw
|
||||||
;; Creates the draw object that handles all rendering.
|
;; Creates the draw object that handles all rendering.
|
||||||
(define (make-draw width height)
|
(define (make-draw width height)
|
||||||
(let ((window (make-window width height "Pacman")))
|
(let ((window (make-window width height "PAC-MAN")))
|
||||||
|
|
||||||
((window 'set-background!) "black")
|
((window 'set-background!) color-background)
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Layers (order determines draw order)
|
;; Layers (order determines draw order)
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
(define header-layer ((window 'new-layer!)))
|
||||||
(define maze-layer ((window 'new-layer!)))
|
(define maze-layer ((window 'new-layer!)))
|
||||||
(define coins-layer ((window 'new-layer!)))
|
(define coins-layer ((window 'new-layer!)))
|
||||||
(define key-layer ((window 'new-layer!)))
|
(define key-layer ((window 'new-layer!)))
|
||||||
(define pacman-layer ((window 'new-layer!)))
|
(define pacman-layer ((window 'new-layer!)))
|
||||||
(define ui-layer ((window 'new-layer!)))
|
(define ui-layer ((window 'new-layer!)))
|
||||||
(define pause-layer ((window 'new-layer!)))
|
(define overlay-layer ((window 'new-layer!)))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Maze tiles
|
;; Header bar — static, drawn once
|
||||||
|
;;
|
||||||
|
|
||||||
|
(define header-tile (make-tile width header-height))
|
||||||
|
((header-layer 'add-drawable!) header-tile)
|
||||||
|
|
||||||
|
;; draw-header! :: -> /
|
||||||
|
;; Draws the static header with the PAC-MAN title.
|
||||||
|
(define (draw-header!)
|
||||||
|
((header-tile 'draw-rectangle!) 0 0 width header-height color-header-bg)
|
||||||
|
((header-tile 'draw-text!)
|
||||||
|
"PAC-MAN" header-title-size header-title-x header-title-y color-title))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; Maze tile
|
||||||
;;
|
;;
|
||||||
|
|
||||||
(define maze-tile (make-tile width height))
|
(define maze-tile (make-tile width height))
|
||||||
@@ -60,7 +75,7 @@
|
|||||||
((key-sprite 'set-scale!) sprite-scale-key)
|
((key-sprite 'set-scale!) sprite-scale-key)
|
||||||
((key-layer 'add-drawable!) key-sprite)
|
((key-layer 'add-drawable!) key-sprite)
|
||||||
|
|
||||||
;; Key UI indicator (next to the score)
|
;; Key UI indicator (shown in header when taken)
|
||||||
(define key-ui-sprite (make-bitmap-tile "pacman-sprites/key.png"))
|
(define key-ui-sprite (make-bitmap-tile "pacman-sprites/key.png"))
|
||||||
((key-ui-sprite 'set-scale!) sprite-scale-key-ui)
|
((key-ui-sprite 'set-scale!) sprite-scale-key-ui)
|
||||||
((key-ui-sprite 'set-x!) key-ui-x)
|
((key-ui-sprite 'set-x!) key-ui-x)
|
||||||
@@ -83,7 +98,7 @@
|
|||||||
(define time-since-last-animation 0)
|
(define time-since-last-animation 0)
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; UI tiles
|
;; UI tile (score + time — redrawn on change)
|
||||||
;;
|
;;
|
||||||
|
|
||||||
(define ui-tile (make-tile width height))
|
(define ui-tile (make-tile width height))
|
||||||
@@ -95,9 +110,9 @@
|
|||||||
|
|
||||||
(define cached-score -1)
|
(define cached-score -1)
|
||||||
(define cached-time "")
|
(define cached-time "")
|
||||||
(define cached-key-taken? #f)
|
|
||||||
(define key-sprite-swapped? #f)
|
(define key-sprite-swapped? #f)
|
||||||
(define cached-paused? #f)
|
(define cached-paused? #f)
|
||||||
|
(define cached-time-up? #f)
|
||||||
(define coins-dirty? #t)
|
(define coins-dirty? #t)
|
||||||
|
|
||||||
;;
|
;;
|
||||||
@@ -117,8 +132,7 @@
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
;; draw-maze! :: maze -> /
|
;; draw-maze! :: maze -> /
|
||||||
;; Draws all walls and doors. Called once at startup and after door
|
;; Draws all walls and doors.
|
||||||
;; removal — never per-frame.
|
|
||||||
(define (draw-maze! maze)
|
(define (draw-maze! maze)
|
||||||
((maze-tile 'clear!))
|
((maze-tile 'clear!))
|
||||||
((maze 'for-each-cell)
|
((maze 'for-each-cell)
|
||||||
@@ -130,28 +144,35 @@
|
|||||||
(grid->pixel-y row)
|
(grid->pixel-y row)
|
||||||
(- cell-size-px maze-wall-shrink)
|
(- cell-size-px maze-wall-shrink)
|
||||||
(- cell-size-px maze-wall-shrink)
|
(- cell-size-px maze-wall-shrink)
|
||||||
"blue"))
|
color-wall))
|
||||||
((= cell-type cell-type-door)
|
((= cell-type cell-type-door)
|
||||||
((maze-tile 'draw-rectangle!)
|
((maze-tile 'draw-rectangle!)
|
||||||
(grid->pixel-x col)
|
(grid->pixel-x col)
|
||||||
(grid->pixel-y row)
|
(grid->pixel-y row)
|
||||||
(- cell-size-px maze-wall-shrink)
|
(- cell-size-px maze-wall-shrink)
|
||||||
(- cell-size-px maze-wall-shrink)
|
(- cell-size-px maze-wall-shrink)
|
||||||
"pink"))))))
|
color-door))))))
|
||||||
|
|
||||||
;; draw-coins! :: maze -> /
|
;; draw-coins! :: maze -> /
|
||||||
;; Redraws all coins. Only called when coins-dirty? is true.
|
;; Redraws all coins as small round dots.
|
||||||
(define (draw-coins! maze)
|
(define (draw-coins! maze)
|
||||||
((coins-tile 'clear!))
|
((coins-tile 'clear!))
|
||||||
((maze 'for-each-cell)
|
((maze 'for-each-cell)
|
||||||
(lambda (row col cell-type)
|
(lambda (row col cell-type)
|
||||||
(when (= cell-type cell-type-coin)
|
(when (= cell-type cell-type-coin)
|
||||||
((coins-tile 'draw-rectangle!)
|
((coins-tile 'draw-ellipse!)
|
||||||
(+ (grid->pixel-x col) coin-inset)
|
(+ (grid->pixel-x col) coin-inset)
|
||||||
(+ (grid->pixel-y row) coin-inset)
|
(+ (grid->pixel-y row) coin-inset)
|
||||||
(- cell-size-px (* 2 coin-inset) 6)
|
coin-size
|
||||||
(- cell-size-px (* 2 coin-inset) 6)
|
coin-size
|
||||||
"yellow")))))
|
color-coin)))))
|
||||||
|
|
||||||
|
;; init-key-position! :: key -> /
|
||||||
|
;; Sets the key sprite to its grid position. Called once at startup.
|
||||||
|
(define (init-key-position! key-obj)
|
||||||
|
(let ((pos (key-obj 'position)))
|
||||||
|
((key-sprite 'set-x!) (grid->pixel-x (pos 'col)))
|
||||||
|
((key-sprite 'set-y!) (grid->pixel-y (pos 'row)))))
|
||||||
|
|
||||||
;; draw-key! :: key -> /
|
;; draw-key! :: key -> /
|
||||||
;; Swaps the key sprite once when taken. No-op on subsequent frames.
|
;; Swaps the key sprite once when taken. No-op on subsequent frames.
|
||||||
@@ -170,8 +191,7 @@
|
|||||||
(set! time-since-last-animation 0)))
|
(set! time-since-last-animation 0)))
|
||||||
|
|
||||||
;; draw-pacman! :: pacman -> /
|
;; draw-pacman! :: pacman -> /
|
||||||
;; Updates Pac-Man position and rotation. Lightweight — just sets
|
;; Updates Pac-Man position and rotation.
|
||||||
;; properties on an existing sprite.
|
|
||||||
(define (draw-pacman! pacman)
|
(define (draw-pacman! pacman)
|
||||||
(let* ((pos (pacman 'position))
|
(let* ((pos (pacman 'position))
|
||||||
(direction (pacman 'direction)))
|
(direction (pacman 'direction)))
|
||||||
@@ -190,44 +210,60 @@
|
|||||||
(when (or (not (= current-score cached-score))
|
(when (or (not (= current-score cached-score))
|
||||||
(not (string=? current-time cached-time)))
|
(not (string=? current-time cached-time)))
|
||||||
((ui-tile 'clear!))
|
((ui-tile 'clear!))
|
||||||
;; Score
|
;; Score label
|
||||||
|
((ui-tile 'draw-text!)
|
||||||
|
"SCORE" score-label-size score-label-x score-label-y color-text)
|
||||||
|
;; Score value
|
||||||
((ui-tile 'draw-text!)
|
((ui-tile 'draw-text!)
|
||||||
(number->string current-score)
|
(number->string current-score)
|
||||||
score-text-size score-text-x score-text-y "white")
|
score-value-size score-value-x score-value-y color-text)
|
||||||
;; Separator line
|
;; Sidebar separator
|
||||||
((ui-tile 'draw-rectangle!)
|
((ui-tile 'draw-rectangle!)
|
||||||
separator-x 0 separator-width height "white")
|
sidebar-x 0 sidebar-width height color-wall)
|
||||||
;; Time limit
|
;; Time label
|
||||||
((ui-tile 'draw-text!)
|
((ui-tile 'draw-text!)
|
||||||
"Time remaining:" time-text-size time-label-x time-label-y "white")
|
"TIME" time-label-size time-label-x time-label-y color-text)
|
||||||
|
;; Time value
|
||||||
((ui-tile 'draw-text!)
|
((ui-tile 'draw-text!)
|
||||||
current-time
|
current-time
|
||||||
score-text-size time-value-x time-value-y "white")
|
time-value-size time-value-x time-value-y color-text)
|
||||||
;; Update cache
|
;; Update cache
|
||||||
(set! cached-score current-score)
|
(set! cached-score current-score)
|
||||||
(set! cached-time current-time))))
|
(set! cached-time current-time))))
|
||||||
|
|
||||||
|
;; draw-game-over! :: boolean -> /
|
||||||
|
;; Shows GAME OVER when time is up.
|
||||||
|
(define (draw-game-over! time-up?)
|
||||||
|
(when (and time-up? (not cached-time-up?))
|
||||||
|
(let ((overlay-tile (make-tile width height)))
|
||||||
|
((overlay-layer 'add-drawable!) overlay-tile)
|
||||||
|
((overlay-tile 'draw-rectangle!)
|
||||||
|
0 (- game-over-text-y 20) 672 100 color-background)
|
||||||
|
((overlay-tile 'draw-text!)
|
||||||
|
"GAME OVER" game-over-text-size
|
||||||
|
game-over-text-x game-over-text-y color-game-over))
|
||||||
|
(set! cached-time-up? #t)))
|
||||||
|
|
||||||
;; draw-pause! :: boolean -> /
|
;; draw-pause! :: boolean -> /
|
||||||
;; Only redraws when pause state actually changes.
|
;; Only redraws when pause state actually changes.
|
||||||
(define (draw-pause! paused?)
|
(define (draw-pause! paused?)
|
||||||
(when (not (eq? paused? cached-paused?))
|
(when (not (eq? paused? cached-paused?))
|
||||||
((pause-layer 'empty!))
|
((overlay-layer 'empty!))
|
||||||
(when paused?
|
(when paused?
|
||||||
(let ((pause-tile (make-tile width height)))
|
(let ((overlay-tile (make-tile width height)))
|
||||||
((pause-layer 'add-drawable!) pause-tile)
|
((overlay-layer 'add-drawable!) overlay-tile)
|
||||||
((pause-tile 'draw-rectangle!) 0 90 670 height "black")
|
((overlay-tile 'draw-rectangle!)
|
||||||
((pause-tile 'draw-text!) "Game Paused" 40 200 400 "red")))
|
0 maze-offset-y 672 (- height maze-offset-y) color-pause-bg)
|
||||||
|
((overlay-tile 'draw-text!)
|
||||||
|
"PAUSED" pause-text-size
|
||||||
|
pause-text-x pause-text-y color-pause-text)))
|
||||||
(set! cached-paused? paused?)))
|
(set! cached-paused? paused?)))
|
||||||
|
|
||||||
;; mark-coins-dirty! :: -> /
|
;; mark-coins-dirty! :: -> /
|
||||||
;; Called by the game when a coin is eaten, so coins are redrawn
|
|
||||||
;; next frame.
|
|
||||||
(define (mark-coins-dirty!)
|
(define (mark-coins-dirty!)
|
||||||
(set! coins-dirty? #t))
|
(set! coins-dirty? #t))
|
||||||
|
|
||||||
;; mark-maze-dirty! :: -> /
|
;; mark-maze-dirty! :: -> /
|
||||||
;; Called by the game when a door is removed, so the maze is
|
|
||||||
;; redrawn next frame.
|
|
||||||
(define (mark-maze-dirty!)
|
(define (mark-maze-dirty!)
|
||||||
(set! coins-dirty? #t))
|
(set! coins-dirty? #t))
|
||||||
|
|
||||||
@@ -238,7 +274,8 @@
|
|||||||
;; draw-game! :: game -> /
|
;; draw-game! :: game -> /
|
||||||
;; Draws the full game. Only redraws changed elements.
|
;; Draws the full game. Only redraws changed elements.
|
||||||
(define (draw-game! game)
|
(define (draw-game! game)
|
||||||
(let ((level (game 'level)))
|
(let* ((level (game 'level))
|
||||||
|
(timer (level 'timer)))
|
||||||
;; Always update (lightweight sprite property sets)
|
;; Always update (lightweight sprite property sets)
|
||||||
(draw-pacman! (level 'pacman))
|
(draw-pacman! (level 'pacman))
|
||||||
;; Only redraw when dirty / changed
|
;; Only redraw when dirty / changed
|
||||||
@@ -247,8 +284,9 @@
|
|||||||
(draw-coins! (level 'maze))
|
(draw-coins! (level 'maze))
|
||||||
(draw-maze! (level 'maze))
|
(draw-maze! (level 'maze))
|
||||||
(set! coins-dirty? #f))
|
(set! coins-dirty? #f))
|
||||||
(draw-ui! (level 'score) (level 'timer))
|
(draw-ui! (level 'score) timer)
|
||||||
(draw-pause! (level 'paused?))))
|
(draw-pause! (level 'paused?))
|
||||||
|
(draw-game-over! ((timer 'time-up?)))))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Callback registration
|
;; Callback registration
|
||||||
@@ -265,12 +303,16 @@
|
|||||||
;; start-drawing! :: game -> /
|
;; start-drawing! :: game -> /
|
||||||
;; Starts drawing by setting the draw callback.
|
;; Starts drawing by setting the draw callback.
|
||||||
(define (start-drawing! game)
|
(define (start-drawing! game)
|
||||||
;; Initial draw (one-time)
|
(let ((level (game 'level)))
|
||||||
(draw-maze! ((game 'level) 'maze))
|
;; Static elements (drawn once)
|
||||||
(draw-coins! ((game 'level) 'maze))
|
(draw-header!)
|
||||||
|
(draw-maze! (level 'maze))
|
||||||
|
(draw-coins! (level 'maze))
|
||||||
|
(init-key-position! (level 'key))
|
||||||
(set! coins-dirty? #f)
|
(set! coins-dirty? #f)
|
||||||
|
;; Register draw callback
|
||||||
((window 'set-draw-callback!)
|
((window 'set-draw-callback!)
|
||||||
(lambda () (draw-game! game))))
|
(lambda () (draw-game! game)))))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Dispatch
|
;; Dispatch
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
;; Coin rendering
|
;; Coin rendering
|
||||||
coin-inset
|
coin-inset
|
||||||
|
coin-size
|
||||||
|
|
||||||
;; Sprites
|
;; Sprites
|
||||||
sprite-scale-pacman
|
sprite-scale-pacman
|
||||||
@@ -56,19 +57,45 @@
|
|||||||
rotation-up
|
rotation-up
|
||||||
rotation-down
|
rotation-down
|
||||||
|
|
||||||
;; UI positions
|
;; Colors
|
||||||
score-text-size
|
color-background
|
||||||
score-text-x
|
color-wall
|
||||||
score-text-y
|
color-door
|
||||||
time-text-size
|
color-coin
|
||||||
|
color-text
|
||||||
|
color-title
|
||||||
|
color-header-bg
|
||||||
|
color-game-over
|
||||||
|
color-pause-bg
|
||||||
|
color-pause-text
|
||||||
|
|
||||||
|
;; UI layout
|
||||||
|
header-height
|
||||||
|
header-title-size
|
||||||
|
header-title-x
|
||||||
|
header-title-y
|
||||||
|
score-label-size
|
||||||
|
score-label-x
|
||||||
|
score-label-y
|
||||||
|
score-value-size
|
||||||
|
score-value-x
|
||||||
|
score-value-y
|
||||||
|
key-ui-x
|
||||||
|
key-ui-y
|
||||||
|
sidebar-x
|
||||||
|
sidebar-width
|
||||||
|
time-label-size
|
||||||
time-label-x
|
time-label-x
|
||||||
time-label-y
|
time-label-y
|
||||||
|
time-value-size
|
||||||
time-value-x
|
time-value-x
|
||||||
time-value-y
|
time-value-y
|
||||||
separator-x
|
game-over-text-size
|
||||||
separator-width
|
game-over-text-x
|
||||||
key-ui-x
|
game-over-text-y
|
||||||
key-ui-y)
|
pause-text-size
|
||||||
|
pause-text-x
|
||||||
|
pause-text-y)
|
||||||
|
|
||||||
(begin
|
(begin
|
||||||
|
|
||||||
@@ -88,8 +115,9 @@
|
|||||||
(define cell-type-key 3)
|
(define cell-type-key 3)
|
||||||
(define cell-type-door 4)
|
(define cell-type-door 4)
|
||||||
|
|
||||||
;; Coin rendering: inset in pixels from cell edge
|
;; Coin rendering
|
||||||
(define coin-inset 7)
|
(define coin-inset 9)
|
||||||
|
(define coin-size 6)
|
||||||
|
|
||||||
;; Sprite scale factors
|
;; Sprite scale factors
|
||||||
(define sprite-scale-pacman 1.5)
|
(define sprite-scale-pacman 1.5)
|
||||||
@@ -119,22 +147,54 @@
|
|||||||
(define rotation-up 90)
|
(define rotation-up 90)
|
||||||
(define rotation-down -90)
|
(define rotation-down -90)
|
||||||
|
|
||||||
;; UI positions for score display
|
;; Colors — arcade-style palette (standard Racket color names only)
|
||||||
(define score-text-size 40)
|
(define color-background "black")
|
||||||
(define score-text-x 560)
|
(define color-wall "medium blue")
|
||||||
(define score-text-y 20)
|
(define color-door "hot pink")
|
||||||
|
(define color-coin "gold")
|
||||||
|
(define color-text "white")
|
||||||
|
(define color-title "yellow")
|
||||||
|
(define color-header-bg "dark slate gray")
|
||||||
|
(define color-game-over "red")
|
||||||
|
(define color-pause-bg "black")
|
||||||
|
(define color-pause-text "red")
|
||||||
|
|
||||||
;; UI positions for time display (right side of separator)
|
;; UI layout — header bar at the top
|
||||||
(define time-text-size 35)
|
(define header-height 90)
|
||||||
(define time-label-x 710)
|
(define header-title-size 36)
|
||||||
(define time-label-y 300)
|
(define header-title-x 250)
|
||||||
(define time-value-x 800)
|
(define header-title-y 25)
|
||||||
(define time-value-y 400)
|
|
||||||
|
|
||||||
;; Separator line between play field and UI
|
;; Score display (left side of header)
|
||||||
(define separator-x 670)
|
(define score-label-size 20)
|
||||||
(define separator-width 24)
|
(define score-label-x 20)
|
||||||
|
(define score-label-y 25)
|
||||||
|
(define score-value-size 32)
|
||||||
|
(define score-value-x 20)
|
||||||
|
(define score-value-y 50)
|
||||||
|
|
||||||
;; Key UI position (next to score)
|
;; Key UI indicator position
|
||||||
(define key-ui-x 20)
|
(define key-ui-x 600)
|
||||||
(define key-ui-y 35)))
|
(define key-ui-y 30)
|
||||||
|
|
||||||
|
;; Sidebar (right of maze)
|
||||||
|
(define sidebar-x 672)
|
||||||
|
(define sidebar-width 4)
|
||||||
|
|
||||||
|
;; Time display (right sidebar area)
|
||||||
|
(define time-label-size 20)
|
||||||
|
(define time-label-x 700)
|
||||||
|
(define time-label-y 200)
|
||||||
|
(define time-value-size 40)
|
||||||
|
(define time-value-x 710)
|
||||||
|
(define time-value-y 240)
|
||||||
|
|
||||||
|
;; Game over overlay
|
||||||
|
(define game-over-text-size 48)
|
||||||
|
(define game-over-text-x 180)
|
||||||
|
(define game-over-text-y 380)
|
||||||
|
|
||||||
|
;; Pause overlay
|
||||||
|
(define pause-text-size 48)
|
||||||
|
(define pause-text-x 200)
|
||||||
|
(define pause-text-y 400)))
|
||||||
|
|||||||
Reference in New Issue
Block a user