summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2d/coroutine.scm18
-rw-r--r--README.org51
-rw-r--r--examples/coroutine.scm20
3 files changed, 54 insertions, 35 deletions
diff --git a/2d/coroutine.scm b/2d/coroutine.scm
index 036cdc4..322f236 100644
--- a/2d/coroutine.scm
+++ b/2d/coroutine.scm
@@ -22,14 +22,15 @@
;;; Code:
(define-module (2d coroutine)
- #:export (coroutine
+ #:export (call-with-coroutine
+ coroutine
colambda
codefine
codefine*)
#:replace (yield))
-(define (coroutine thunk)
- "Calls a procedure that can yield a continuation."
+(define (call-with-coroutine thunk)
+ "Apply THUNK with a coroutine prompt."
(define (handler cont callback . args)
(define (resume . args)
;; Call continuation that resumes the procedure.
@@ -42,11 +43,16 @@
;; Call procedure.
(call-with-prompt 'coroutine-prompt thunk handler))
+;; emacs: (put 'coroutine 'scheme-indent-function 0)
+(define-syntax-rule (coroutine body ...)
+ "Evaluate BODY as a coroutine."
+ (call-with-coroutine (lambda () body ...)))
+
;; emacs: (put 'colambda 'scheme-indent-function 1)
(define-syntax-rule (colambda args body ...)
"Syntacic sugar for a lambda that is run as a coroutine."
(lambda args
- (coroutine
+ (call-with-coroutine
(lambda () body ...))))
;; emacs: (put 'codefine 'scheme-indent-function 1)
@@ -57,7 +63,7 @@ coroutine."
;; Create an inner procedure with the same signature so that a
;; recursive procedure call does not create a new prompt.
(define (name ...) . body)
- (coroutine
+ (call-with-coroutine
(lambda () (name ...)))))
;; emacs: (put 'codefine* 'scheme-indent-function 1)
@@ -68,7 +74,7 @@ coroutine."
;; Create an inner procedure with the same signature so that a
;; recursive procedure call does not create a new prompt.
(define* (name . formals) . body)
- (coroutine
+ (call-with-coroutine
(lambda () (apply name args)))))
(define (yield callback)
diff --git a/README.org b/README.org
index 50a70b8..bee725e 100644
--- a/README.org
+++ b/README.org
@@ -168,33 +168,48 @@
exists a =wait= procedure to pause a coroutine and schedule it to
be resumed later.
- Using a coroutine and the agenda, the NPC script can be rewritten
+ Using a coroutine and an agenda, the NPC script can be rewritten
such that it does not halt further program execution.
#+BEGIN_SRC scheme
(use-modules (2d agenda)
- (2d coroutine))
+ (2d coroutine)
+ (2d game))
- (schedule-next
- (colambda ()
- (while #t
- (walk 'up)
- (wait 60)
- (walk 'down)
- (wait 60))))
+ (coroutine
+ (while #t
+ (walk 'up)
+ (wait game-agenda 60)
+ (walk 'down)
+ (wait game-agenda 60)))
#+END_SRC
- =colambda= is a useful macro that is syntactic sugar for a lambda
- expression executed as a coroutine. =schedule-next= accepts a
- thunk (a procedure that takes 0 arguments) and schedules it to be
- executed the next time the agenda is ticked. There are other ways
- to schedule procedures such as =schedule=, =schedule-interval=,
- and =schedule-every=.
+ =coroutine= is a useful macro that evaluates a block of code as a
+ coroutine. =wait= aborts the procedure and schedules the
+ continuation inside of an agenda. =game-agenda= is the main
+ agenda that is ticked at each iteration of the game update loop.
+ In this example, the script is paused for 1 second after each
+ step. Since guile-2d enforces a fixed timestep and updates 60
+ times per second by default, 60 ticks is equivalent to 1 second.
- Since guile-2d enforces a fixed timestep and updates 60 times per
- second by default, waiting for 60 updates means that the NPC will
- wait one second in between each step.
+ You can also use the agenda to schedule the evaluation of any
+ thunk even if it isn't a coroutine.
+
+ #+BEGIN_SRC scheme
+ (define (hello)
+ (display "Hello, world! Sorry I'm late!\n"))
+
+ (schedule game-agenda hello 600)
+ #+END_SRC
+
+ =schedule= accepts a thunk (a procedure that takes no arguments)
+ and schedules it to be applied after a certain number of ticks, or
+ after 1 tick by default. In this example, the text "Hello, world!
+ Sorry I'm late!" is displayed after 10 seconds. There are other
+ ways to schedule procedures, too. =schedule-interval= applies a
+ thunk periodically, and =schedule-each= applies a thunk upon every
+ tick.
** REPL Driven Development
diff --git a/examples/coroutine.scm b/examples/coroutine.scm
index a479a66..45e8b39 100644
--- a/examples/coroutine.scm
+++ b/examples/coroutine.scm
@@ -15,17 +15,15 @@
;; Simple script that moves the sprite to a random location every
;; second.
-(codefine (script)
- (set-sprite-position!
- sprite
- (vector2 (random window-width)
- (random window-height)))
- (wait game-agenda 15)
- (set-sprite-rotation! sprite (random 360))
- (wait game-agenda 15)
- (script))
-
-(schedule game-agenda script)
+(coroutine
+ (while #t
+ (set-sprite-position!
+ sprite
+ (vector2 (random window-width)
+ (random window-height)))
+ (wait game-agenda 15)
+ (set-sprite-rotation! sprite (random 360))
+ (wait game-agenda 15)))
(add-hook! draw-hook (lambda (dt alpha) (draw-sprite sprite)))