Fix interpolation: use offset backward lerp instead of forward extrapolation

Forward extrapolation caused visible teleporting at every direction
change (ghosts jumping ~1.3 tiles at intersections). Replace with
lerp(prev, current, 0.5 + t/2) which starts the visual at the
midpoint (max 0.5 tile / 12px lag) and smoothly reaches the
destination. No jumps, no teleporting, minimal hitbox offset.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
joren
2026-03-23 12:00:04 +01:00
parent 5e7456eba9
commit 0e14140db9

View File

@@ -262,9 +262,10 @@
(+ a (* t (- b a)))) (+ a (* t (- b a))))
;; draw-pacman! :: pacman, number -> / ;; draw-pacman! :: pacman, number -> /
;; Draws Pac-Man with forward extrapolation from current position. ;; Draws Pac-Man with offset backward interpolation. Uses
;; Formula: current + (current - prev) * t — visual leads toward ;; lerp(prev, current, 0.5 + t/2) so the visual starts at the
;; the next tile so it aligns with the logical hitbox. ;; midpoint (max 0.5 tile lag) and arrives at current by t=1.
;; No jumps on direction changes unlike forward extrapolation.
(define (draw-pacman! pacman progress) (define (draw-pacman! pacman progress)
(let* ((pos (pacman 'position)) (let* ((pos (pacman 'position))
(row (pos 'row)) (row (pos 'row))
@@ -272,8 +273,9 @@
(prev-row (pacman 'prev-row)) (prev-row (pacman 'prev-row))
(prev-col (pacman 'prev-col)) (prev-col (pacman 'prev-col))
(t (min progress 1)) (t (min progress 1))
(render-row (+ row (* t (- row prev-row)))) (factor (+ 0.5 (* 0.5 t)))
(render-col (+ col (* t (- col prev-col)))) (render-row (lerp prev-row row factor))
(render-col (lerp prev-col col factor))
(direction (pacman 'direction))) (direction (pacman 'direction)))
((pacman-sprite 'set-x!) (grid->pixel-x render-col)) ((pacman-sprite 'set-x!) (grid->pixel-x render-col))
((pacman-sprite 'set-y!) (grid->pixel-y render-row)) ((pacman-sprite 'set-y!) (grid->pixel-y render-row))
@@ -283,7 +285,7 @@
((eq? direction 'down) ((pacman-sprite 'rotate!) rotation-down))))) ((eq? direction 'down) ((pacman-sprite 'rotate!) rotation-down)))))
;; draw-ghosts! :: list -> / ;; draw-ghosts! :: list -> /
;; Updates all ghost sprite positions with forward extrapolation. ;; Updates all ghost sprite positions with offset backward interpolation.
(define (draw-ghosts! ghosts) (define (draw-ghosts! ghosts)
(for-each (for-each
(lambda (ghost ghost-draw) (lambda (ghost ghost-draw)
@@ -293,8 +295,9 @@
(prev-row (ghost 'prev-row)) (prev-row (ghost 'prev-row))
(prev-col (ghost 'prev-col)) (prev-col (ghost 'prev-col))
(t (min (/ (ghost 'movement-timer) ghost-speed-ms) 1)) (t (min (/ (ghost 'movement-timer) ghost-speed-ms) 1))
(render-row (+ row (* t (- row prev-row)))) (factor (+ 0.5 (* 0.5 t)))
(render-col (+ col (* t (- col prev-col)))) (render-row (lerp prev-row row factor))
(render-col (lerp prev-col col factor))
(dir (ghost 'direction))) (dir (ghost 'direction)))
((ghost-draw 'update!) render-row render-col dir))) ((ghost-draw 'update!) render-row render-col dir)))
ghosts ghost-draw-states)) ghosts ghost-draw-states))