summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorDavid Thompson <dthompson2@worcester.edu>2016-04-18 20:39:39 -0400
committerDavid Thompson <dthompson2@worcester.edu>2016-04-18 20:39:39 -0400
commit9972e5c26da25c29939e5a75f59db5d58c14a31c (patch)
tree498b4a906b7afe4105b3677d2e5f5c7fa075c7cd /doc
parent049964583b191f2302ff666f97ca23417b80762e (diff)
Add actor module.
* sly/actor.scm: New file. * Makefile.am (SOURCES): Add it. * doc/api/scripting.texi: New file. * doc/Makefile.am (sly_TEXINFOS): Add it. * doc/sly.texi: Include scripting section. * .dir-locals.el: Add identing rule for call-with-actor.
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/api/scripting.texi238
-rw-r--r--doc/sly.texi2
3 files changed, 241 insertions, 0 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 4f7d4a2..abf5170 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -9,6 +9,7 @@ sly_TEXINFOS = \
api/time.texi \
api/input.texi \
api/rendering.texi \
+ api/scripting.texi \
api/utils.texi
dvi: # Don't build dvi docs
diff --git a/doc/api/scripting.texi b/doc/api/scripting.texi
new file mode 100644
index 0000000..ca2cfd4
--- /dev/null
+++ b/doc/api/scripting.texi
@@ -0,0 +1,238 @@
+@node Scripting
+@section Scripting
+
+@menu
+* Overview:: Scripting basics.
+* Actors:: Scriptable game objects.
+* Actions:: Action combinators.
+@end menu
+
+@node Overview
+@subsection Overview
+
+@example
+(use-modules (sly actor))
+@end example
+
+An actor associates an object within the game world with a ``script''
+to control that object. For example, one can control a non-player
+character's movements in a role-playing game with an actor script.
+Or, a shoot-em-up game could make the game world itself an actor whose
+script adds enemies to the world at designated times. Like all
+high-level interfaces in Sly, it is purely functional.
+
+An actor is a wrapper around another game object. To create an actor,
+use the @code{make-actor} constructor:
+
+@example
+(make-actor (make-enemy) script)
+@end example
+
+Each script is composed of ``actions'', which are procedures that
+perform a user-defined transformation on a game object. Action
+procedures take three arguments: The ``world'', the ``effects'' list,
+and the game object itself.
+
+The world is an object that the action can query as part of its logic.
+For example, an enemy action that shot a bullet aimed at the player
+could query the world to find out the current location of the player.
+
+An effect is a procedure generated by an action that alters the game
+world rather than the actor itself. Going back to the previous
+example, in order for the enemy to actually shoot a bullet it would
+have to add to the effects list, because adding a bullet alters the
+world, not the actor.
+
+An action must return three values: the next action (or @code{#f} if
+there is nothing left to do), the new effects lists, and the new game
+object. Let's take a look at the simplest possible action,
+@code{idle}, which does not change the game object, nor add an effect,
+nor do anything else afterwards:
+
+@example
+(define (idle world effects object)
+ (values #f effects object))
+@end example
+
+Now for something a bit more complicated. Here's a higher-order
+procedure that returns an action that moves an enemy object
+horizontally:
+
+@example
+(define (move-horizontally x)
+ (lambda (world effects object)
+ (values #f effects (move-enemy object (vector2 x 0)))))
+
+;; Create a new action that moves the enemy by 3 units.
+(move-horizontally 3)
+@end example
+
+But what if one wants to wait a turn and then move horizontally?
+Enter action combinators, which allow multiple, simpler actions to be
+@emph{composed} into a complex action.
+
+To perform actions one after another, use the @code{sequence}
+combinator:
+
+@example
+(sequence idle
+ (move-horizontally 3)
+ idle
+ (move-horizontally 6))
+@end example
+
+To perform actions at the same time, use the @code{together}
+combinator:
+
+@example
+(together (move-horizontally 3)
+ shoot-at-player)
+@end example
+
+To perform an action in an unbounded loop, use the @code{forever}
+combinator:
+
+@example
+(forever (move-horizontally 3))
+@end example
+
+To perform an action a fixed number of times, use the @code{repeat}
+combinator:
+
+@example
+(repeat 10 (move-horizontally 3))
+@end example
+
+To perform one of two actions depending upon a condition, like
+@code{if} in regular Scheme code, use the @code{ifa} combinator:
+
+@example
+(ifa enemy-close-to-player?
+ shoot-at-player
+ (move-horizontally 3))
+@end example
+
+To take a single step in the actor script, use @code{update-actor}:
+
+@example
+(update-actor game-world effects-list actor)
+@end example
+
+The following sections provide a detailed reference for all of the
+procedures in the scripting interface.
+
+@node Actors
+@subsection Actors
+
+@deffn {Scheme Procedure} make-actor @var{object} @var{action}
+Create a new actor that wraps @var{object}, an arbitrary game object,
+and associates it with @var{action}, an action procedure.
+@end deffn
+
+@deffn {Scheme Procedure} actor? @var{object}
+Return @code{#t} if @var{object} is an actor.
+@end deffn
+
+@deffn {Scheme Procedure} actor-ref @var{actor}
+Return the object stored within @var{actor}.
+@end deffn
+
+@deffn {Scheme Procedure} actor-action @var{actor}
+Return the action for @var{actor}.
+@end deffn
+
+@deffn {Scheme Procedure} update-actor @var{world} @var{effects} @var{actor}
+Apply the action for @var{actor} with the given @var{world}, the game
+world object, and @var{effects}, the effects list.
+@end deffn
+
+@deffn {Scheme Procedure} actor-filter-update @var{predicate} @var{world} @var{actors}
+Update each actor in the list @var{actors} with respect to @var{world}
+and return a new list of actors whose objects satisfy @var{predicate}.
+@end deffn
+
+@deffn {Scheme Procedure} call-with-actor @var{actor} @var{proc}
+Apply @var{proc} with the object stored in @var{actor} and return a
+new actor containing the value returned from @var{proc}. The actor's
+action remains unchanged.
+@end deffn
+
+@node Actions
+@subsection Actions
+
+@deffn {Scheme Procedure} idle @var{world} @var{effects} @var{object}
+Do nothing. Do not change @var{object} nor add anything to
+@var{effects}.
+@end deffn
+
+@deffn {Scheme Procedure} wait @var{duration}
+Create an action that does nothing @var{duration} times.
+@end deffn
+
+@deffn {Scheme Procedure} forever @var{action}
+Create an action that performs @var{action} in an infinite loop, once
+per tick.
+@end deffn
+
+@deffn {Scheme Procedure} sequence @var{actions} @dots{}
+Create an action that sequentially performs each action in the order
+specified in the arguments list.
+@end deffn
+
+@deffn {Scheme Procedure} together @var{actions} @dots{}
+Create an action that concurrently performs each action in the order
+specified in the arguments list.
+@end deffn
+
+@deffn {Scheme Procedure} ifa @var{predicate} @var{consequent} @var{alternate}
+Create an action that performs @var{consequent} if @var{predicate} is
+satisfied, or @var{alternate} otherwise. @var{predicate} is a
+procedure that accepts a single argument: The game object stored
+within the actor that is performing the action.
+@end deffn
+
+@deffn {Scheme Procedure} whena @var{predicate} @var{consequent}
+Create an action that performs @var{consequent} when @var{predicate}
+is satisfied, otherwise nothing is done.
+@end deffn
+
+@deffn {Scheme Procedure} unlessa @var{predicate} @var{alternate}
+Create an action that performs @var{alternate} unless @var{predicate}
+is satisfied, otherwise nothing is done.
+@end deffn
+
+@deffn {Scheme Procedure} repeat @var{times} @var{action}
+Create an action that performs @var{action} @var{times} in a row.
+@end deffn
+
+@deffn {Scheme Procedure} action-lift
+Create an action constructor from @var{proc}, a procedure of any
+number of arguments whose first argument is the game object being
+transformed.
+
+@example
+(define (move-player player offset) ...)
+
+(define move-player* (action-lift move-player))
+
+;; Create a new action that moves the player horizontally.
+(move-player* (vector2 10 0))
+@end example
+
+@end deffn
+
+@deffn {Scheme Procedure} both @var{a} @var{b}
+Peform action @var{a} immediately followed by action @var{b}. When
+the action is run, the remainder of both @var{a} and @var{b} are
+returned as the next action to perform.
+
+This is a low-level combinator. Use @code{together} instead.
+@end deffn
+
+@deffn {Scheme Procedure} then @var{a} @var{b}
+Perform action @var{a} followed by action @var{b}. Unlike
+@code{both}, action @var{b} is not performed immediately after @var{a}
+finishes, but rather requires another tick.
+
+This is a low-level combinator. Use @code{sequence} instead.
+@end deffn
diff --git a/doc/sly.texi b/doc/sly.texi
index e0c081d..127f52b 100644
--- a/doc/sly.texi
+++ b/doc/sly.texi
@@ -167,6 +167,7 @@ See their respective home pages for installation and usage instructions.
* Booting:: Opening a window and running the game loop.
* Math:: Vectors, quaternions, matrices, etc.
* Time:: Tick-tock.
+* Scripting:: Functional game object scripting.
* Input:: Keyboard, mouse, and joystick input.
* Rendering:: Drawing to the screen.
* Utilities:: Miscellaneous conveniences.
@@ -175,6 +176,7 @@ See their respective home pages for installation and usage instructions.
@include api/init.texi
@include api/math.texi
@include api/time.texi
+@include api/scripting.texi
@include api/input.texi
@include api/rendering.texi
@include api/utils.texi