From 83c8d25bc69186db996c255cffc5030c0e54eb97 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Tue, 21 Sep 2021 20:10:58 -0400 Subject: game-loop: Add current-timestep parameter. --- chickadee.scm | 3 +- chickadee/game-loop.scm | 82 ++++++++++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/chickadee.scm b/chickadee.scm index aec8eef..c8ad719 100644 --- a/chickadee.scm +++ b/chickadee.scm @@ -77,7 +77,8 @@ warp-mouse set-show-cursor! run-game) - #:re-export (abort-game)) + #:re-export (abort-game + current-timestep)) (define %time-freq (exact->inexact (sdl-performance-frequency))) diff --git a/chickadee/game-loop.scm b/chickadee/game-loop.scm index 027d7af..76e649a 100644 --- a/chickadee/game-loop.scm +++ b/chickadee/game-loop.scm @@ -17,7 +17,8 @@ (define-module (chickadee game-loop) #:export (run-game* - abort-game)) + abort-game + current-timestep)) ;;; @@ -56,44 +57,47 @@ (define (abort-game) (abort-to-prompt game-loop-prompt-tag #f)) -(define* (run-game* #:key update render time error +(define current-timestep (make-parameter 0.0)) + +(define* (run-game* #:key init update render time error (update-hz 60)) (let ((timestep (/ 1.0 update-hz))) - (call-with-prompt game-loop-prompt-tag - (lambda () - ;; Catch SIGINT and kill the loop. - (sigaction SIGINT - (lambda (signum) - (abort-game))) - (init) - ;; A simple analogy is that we are filling up a bucket - ;; with water. When the bucket fills up to a marked - ;; line, we dump it out. Our water is time, and each - ;; time we dump the bucket we update the game. Updating - ;; the game on a fixed timestep like this yields a - ;; stable simulation. - (let loop ((previous-time (time)) - (buffer 0.0)) - (let* ((current-time (time)) - (delta (- current-time previous-time))) - (let update-loop ((buffer (+ buffer delta))) - (if (>= buffer timestep) - ;; Short-circuit the update loop if an error - ;; occurred, and reset the current time to now in - ;; order to discard the undefined amount of time - ;; that was spent handling the error. - (if (with-error-handling error (update timestep)) - (loop (time) 0.0) - (update-loop (- buffer timestep))) - (begin - ;; We render upon every iteration of the loop, and - ;; thus rendering is decoupled from updating. - ;; It's possible to render multiple times before - ;; an update is performed. - (if (with-error-handling error - (render (/ buffer timestep)) - (usleep 1)) + (parameterize ((current-timestep timestep)) + (call-with-prompt game-loop-prompt-tag + (lambda () + ;; Catch SIGINT and kill the loop. + (sigaction SIGINT + (lambda (signum) + (abort-game))) + (init) + ;; A simple analogy is that we are filling up a bucket + ;; with water. When the bucket fills up to a marked + ;; line, we dump it out. Our water is time, and each + ;; time we dump the bucket we update the game. Updating + ;; the game on a fixed timestep like this yields a + ;; stable simulation. + (let loop ((previous-time (time)) + (buffer 0.0)) + (let* ((current-time (time)) + (delta (- current-time previous-time))) + (let update-loop ((buffer (+ buffer delta))) + (if (>= buffer timestep) + ;; Short-circuit the update loop if an error + ;; occurred, and reset the current time to now in + ;; order to discard the undefined amount of time + ;; that was spent handling the error. + (if (with-error-handling error (update timestep)) (loop (time) 0.0) - (loop current-time buffer)))))))) - (lambda (cont callback) - #f)))) + (update-loop (- buffer timestep))) + (begin + ;; We render upon every iteration of the loop, and + ;; thus rendering is decoupled from updating. + ;; It's possible to render multiple times before + ;; an update is performed. + (if (with-error-handling error + (render (/ buffer timestep)) + (usleep 1)) + (loop (time) 0.0) + (loop current-time buffer)))))))) + (lambda (cont callback) + #f))))) -- cgit v1.2.3