diff options
-rw-r--r-- | doc/Makefile.am | 23 | ||||
-rw-r--r-- | doc/api/signals.texi | 214 | ||||
-rw-r--r-- | doc/sly.texi | 142 |
3 files changed, 340 insertions, 39 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am index 9c2d95e..b26a64e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -2,23 +2,6 @@ AUTOMAKE_OPTIONS = gnu info_TEXINFOS = sly.texi -guile_TEXINFOS = audio.texi \ - fdl.texi \ - game.texi \ - graphics.texi \ - graphics/animation.texi \ - graphics/color.texi \ - graphics/font.texi \ - graphics/sprite.texi \ - graphics/texture.texi \ - graphics/tileset.texi \ - sly.texi \ - introduction.texi \ - math.texi \ - math/math.texi \ - math/rect.texi \ - math/vector2.texi \ - scripting.texi \ - scripting/actions.texi \ - scripting/agenda.texi \ - scripting/coroutine.texi +sly_TEXINFOS = \ + fdl.texi \ + api/signals.texi diff --git a/doc/api/signals.texi b/doc/api/signals.texi new file mode 100644 index 0000000..a4e2c01 --- /dev/null +++ b/doc/api/signals.texi @@ -0,0 +1,214 @@ +@node Signals +@section Signals + +Game state is a function of time. The player's score, the current +stage, an enemy's hit points, etc. all change in response to events +that happen at discrete points in time. Typically, this means that a +number of callback procedures are registered to respond to events +which mutate the relevant data structures. However, this approach, +while simple and effective, comes at the price of readability, +reproducibility, and expression. Instead of explicitly mutating data +and entering ``callback hell'', Sly abstracts and formalizes the +process using a functional reactive programming style. + +In Sly, time-varying values are called ``signals'', and they are +defined in a declarative and functional manner. Rather than +describing the process of mutation procedurally, one describes the +relationships between signals instead. The result is a ``signal +graph'', a directed acyclic graph of event responses. + +@example +(define-signal position + (signal-fold v+ (vector2 320 240) + (signal-map (lambda (v) (v* v 4)) + (signal-sample 1 key-arrows)))) +@end example + +This signal describes a relationship between the arrow keys on the +keyboard and the position of the player. @code{signal-sample} is used +to trigger a signal update upon every game tick that provides the +current state of the arrow keys. @code{key-arrows} is a 2D vector +that maps to the current state of the arrow keys, allowing for 8 +directional movement. This vector is then scaled 4x to make the +player move faster. Finally, the scaled vector is added to the +previous player position via @code{signal-fold}. The player's +position is at (320, 240) initially. As you can see, there are no +callbacks and explicit mutation needed, and the position seems to +magically change with the passage of time. + +@deffn {Scheme Procedure} signal? @var{obj} +Return @code{#t} if @var{obj} is a signal. +@end deffn + +@deffn {Scheme Procedure} make-signal @var{value} +Wrap @var{value} in a signal. +@end deffn + +@deffn {Scheme Syntax} define-signal @var{name} @var{value} +Create a top-level signal variable called @var{name}. If the variable +already exists and refers to a signal then its outputs will be spliced +into the new signal. If the given value is not a signal then it will +be put into one via @code{make-signal}. + +@code{define-signal} is particularly useful when working at the REPL. +A top-level signal variable defined by @code{define-signal} can be +redefined at runtime, and the signals that depended on the old signal +will continue to work with the new signal. +@end deffn + +@deffn {Scheme Procedure} signal-ref @var{signal} +Return the value stored within @var{signal}. +@end deffn + +@deffn {Scheme Procedure} signal-ref-maybe object +Return the value stored within @var{object} if @var{object} is a +signal. Otherwise, return @var{object}. +@end deffn + +@deffn {Scheme Syntax} signal-let ((@var{var} @var{signal}) @dots{}) @var{body} @dots{} +Evaluate @var{body} in the context of the local bindings defined by +the two-element lists @code{((var signal) @dots{})}. +@code{signal-let} works like regular @code{let}, except that it +derefences @var{signal} before binding to @var{var}. +@end deffn + +@deffn {Scheme Syntax} signal-let* ((@var{var} @var{signal}) @dots{}) @var{body} @dots{} +Similar to @code{signal-let}, but the variable bindings are performed +sequentially. This means that all initialization expressions are +allowed to use the variables defined to the their left in the binding +list. +@end deffn + +@deffn {Scheme Procedure} signal-set! signal-box value +Change the contents of @var{signal} to @var{value}. This procedure +should almost never be used, except to bootstrap a root node of a +signal graph. +@end deffn + +@deffn {Scheme Procedure} hook->signal @var{hook} @var{init} @var{proc} +Create a new signal whose initial value is @var{init} and whose future +values are calculated by applying @var{proc} to the arguments passed +when @var{hook} is run. +@end deffn + +@deffn {Scheme Procedure} signal-merge @var{signal1} @var{signal2} . @var{rest} +Create a new signal whose value is the that of the most recently +updated signal in @var{signal1}, @var{signal2}, etc. The initial +value is that of @var{signal1}. +@end deffn + +@deffn {Scheme Procedure} signal-zip . @var{signals} +Create a new signal whose value is a list of the values stored in +@var{signals}. +@end deffn + +@deffn {Scheme Procedure} signal-map @var{proc} @var{signal} . @var{rest} +Create a new signal that applies @var{proc} to the values of +@var{SIGNAL}. More than one input signal may be specified, in which +case @var{proc} must accept as many arguments as there are input +signals. +@end deffn + +@deffn {Scheme Procedure} signal-sample-on @var{value-signal} @var{sample-signal} +Create a new signal that takes on the value of @var{value-signal} +whenever @var{sample-signal} receives a new value. +@end deffn + +@deffn {Scheme Procedure} signal-negate @var{signal} +Create a new signal whose value is the negation of @var{signal} by +applying @code{not} to each value received. +@end deffn + +@deffn {Scheme Procedure} signal-fold @var{proc} @var{init} @var{signal} . @var{rest} +Create a new signal that applies @var{proc} with the value received +from @var{signal} and the past value of itself, starting with +@var{init}. Like @code{signal-map}, more than one input signal may be +given. +@end deffn + +@deffn {Scheme Procedure} signal-filter @var{predicate} @var{default} @var{signal} +Create a new signal that takes on the value received from @var{signal} +when it satisfies the procedure @var{predicate}. The value of the +signal is @var{default} in the case that the predicate is never +satisfied. +@end deffn + +@deffn {Scheme Procedure} signal-drop @var{predicate} @var{default} @var{signal} +Create a new signal that takes on the value received from @var{signal} +when it does @emph{not} satisfy the procedure @var{predicate}. The +value of the signal is @var{default} in the case that the predicate is +never satisfied. +@end deffn + +@deffn {Scheme Procedure} signal-drop-repeats @var{signal} [@var{equal?}] +Create a new signal that drops the value received from @var{signal} +when it is equivalent to the current value. By default, @code{equal?} +is used for testing equivalence. +@end deffn + +@deffn {Scheme Procedure} signal-switch @var{predicate} @var{on} @var{off} +Create a new signal whose value is that of the signal @var{on} when +the signal @var{predicate} is true, or the value of the signal +@var{off} otherwise. +@end deffn + +@deffn {Scheme Procedure} signal-constant @var{constant} @var{signal} +Create a new signal whose value is always @var{constant} no matter the +value received from @var{signal}. +@end deffn + +@deffn {Scheme Procedure} signal-count @var{signal} [@var{start}] [@var{step}] +Create a new signal that increments a counter by @var{step} when a +value from @var{signal} is received, starting from @var{start}. By +default, @var{start} is 0 and @var{step} is 1. +@end deffn + +@deffn {Scheme Procedure} signal-tap @var{proc} @var{signal} +Create a new signal that applies @var{proc} for side-effects when a +value from @var{signal} is received. The value of the new signal will +always be the value of @var{signal}. This signal is a convenient way +to sneak in a procedure that with a side-effect into a signal graph. +Such a signal might write text to a file, or play a sound. +@end deffn + +@deffn {Scheme Procedure} signal-timestamp @var{signal} +Create a new signal whose value is a pair, the car of which is the +time that the value of @var{signal} was received and the cdr of which +is the received value. +@end deffn + +@deffn {Scheme Procedure} signal-time @var{signal} +Create a new signal whose value is the time that the value of +@var{signal} was received. +@end deffn + +@deffn {Scheme Procedure} signal-sample @var{step} @var{signal} +Create a new signal that takes on the value of @var{signal} every +@var{step} ticks. +@end deffn + +@deffn {Scheme Procedure} signal-every @var{step} +Create a new signal that emits @var{step} every @var{step} ticks. +@end deffn + +@deffn {Scheme Procedure} signal-since @var{step} @var{signal} +Create a new signal that emits the time since @var{signal} was updated +ever @var{step} ticks. +@end deffn + +@deffn {Scheme Procedure} signal-delay @var{delay} @var{signal} +Create a new signal that delays propagation of @var{signal} by +@var{delay} ticks.. +@end deffn + +@deffn {Scheme Procedure} signal-throttle delay signal +Create a new signal that propagates @var{signal} at most once every +@var{delay} ticks. +@end deffn + +@deffn {Scheme Syntax} signal-generator @var{body} @dots{} +Create a new signal whose value is the most recently yielded value of +the coroutine defined by @var{body}. A special @code{yield} syntax is +available within @var{body} to specify which values are passed to the +signal. +@end deffn diff --git a/doc/sly.texi b/doc/sly.texi index 3898e5d..e70274a 100644 --- a/doc/sly.texi +++ b/doc/sly.texi @@ -4,9 +4,7 @@ @settitle Sly @c %**end of header @copying -Sly is a 2D game development framework for GNU Guile. - -Copyright @copyright{} 2013 David Thompson +Copyright @copyright{} 2013, 2014 David Thompson @email{davet@@gnu.org} @quotation Permission is granted to copy, distribute and/or modify this document @@ -28,8 +26,8 @@ The document was typeset with @titlepage @title Sly 0.1 -@subtitle Sly is a 2D game development framework for GNU Guile -@author David Thompson <dthompson@@member.fsf.org> +@subtitle Using the Sly game engine +@author David Thompson @page @vskip 0pt plus 1filll @insertcopying @@ -47,24 +45,128 @@ The document was typeset with @c Generate the nodes for this menu with `C-c C-u C-m'. @menu -* Introduction:: -* Games and Scenes:: -* Graphics:: -* Audio:: -* Scripting:: -* Math:: -* Copying This Manual:: +* Introduction:: About Sly. +* Installation:: Installing Sly. +* Getting Started:: Writing your first Sly program. +* API Reference:: Sly programming interface. +* Contributing:: Help improve Sly! +* Copying This Manual:: The license of this manual. * Index:: @end menu @c Update all node entries with `C-c C-u C-n'. @c Insert new nodes with `C-c C-c n'. -@include introduction.texi -@include game.texi -@include graphics.texi -@include audio.texi -@include scripting.texi -@include math.texi + +@node Introduction +@chapter Introduction + +Sly is a 2D/3D game engine written in the GNU Guile dialect of the +Scheme programming language. With the help of Guile, Sly provides all +of the essential building blocks for making video games, such as: +window management, input even handling, rendering, linear algebra, and +powerful scripting capabilities. Sly differentiates itself from +traditional game engines by providing a dynamic live coding +environment, functional reactive programming, and a declarative scene +graph. + +Live coding is the practice of improvised interactive programming. +Sly provides a suitable environment for live coding by leveraging +Emacs, Geiser, and Guile's cooperative REPL server. With these tools, +programmers may evaluate arbitrary code and see the effects of their +modifications in real time. This tight feedback loop allows for +faster prototyping, greater productivity, and most importantly, more +fun. + +Functional reactive programming (FRP) is a technique used to model +time-varying values with pure functions. A pure function is a +function that produces no side-effects, such as calling 'set!' on a +variable or writing to the contents of an array. Sly encapsulates +time-varying values in ``signals'', a high-level data structure for +controlling the flow of events. Unlike imperative event callbacks, +signals can easily be composed to form new signals. By modeling game +state with pure functions and immutable data, a game can be seen as a +function of time, in the mathematical sense. Constructing a game this +way allows for deterministic behavior that is easier to reason about +than the accumulation of side-effects seen in traditional game +engines. + +A scene graph is a data structure for positioning renderable objects +relative to one another. Child nodes inherit the transformations +applied to their parent, making it easy to move a large amount of +objects around as a group rather than individually. Sly's implements +a declarative scene graph API, which means that the programmer +describes @emph{what} to render, rather than @emph{how} to render it. + +These three major components form a powerful, high-level environment +for building video games. + +@node Installation +@chapter Installation + +Sly is available for download from its website at +@url{sly.dthompson.us}. This section describes the software +requirements of Sly, as well as how to install it. + +The build procedure for Sly is the same as for GNU software packages, +and is not covered here. Please see the files @file{README.org} and +@file{INSTALL.org} for additional details. + +@menu +* Requirements:: Software needed to build and run Sly. +* Examples:: Run example programs. +@end menu + +@node Requirements +@section Requirements + +Sly depends on the following packages: + +@itemize +@item @url{https://gnu.org/software/guile, GNU Guile}, version 2.0.11 or later; +@item @url{https://gnu.org/software/guile-opengl, GNU guile-opengl}, version 0.1 or later. +@item @url{https://gnu.org/software/guile-sdl, GNU guile-sdl}, version 0.5.0 or later; +@item @url{https://gnu.org/software/gsl, GNU Scientific Library}, version 1.16 or later; +@item @url{http://freeimage.sourceforge.net/, FreeImage}, version 3 or later +@end itemize + +@node Examples +@section Examples + +To test your Sly installation, try running some of the included +example programs. Examples can be found in the +@file{share/sly/examples} directory, relative to the installation +prefix. + +To run an example, invoke Guile with the relevant file, such as: +@code{guile simple.scm}. If successful, a window with a sprite in the +center will open. + +A more complex example can further test your installation and show off +what Sly can do. Try running the ``2048'' example in +@file{share/sly/examples/2048} with @code{guile 2048.scm}. + +@node Getting Started +@chapter Getting Started + +@node API Reference +@chapter API Reference + +@menu +* Signals:: Functional reactive programming. +@end menu + +@include api/signals.texi + +@node Contributing +@chapter Contributing + +This project is a cooperative effort, and we need your help to make it +grow! Please get in touch with us on @code{#sly} on the Freenode IRC +network. We welcome ideas, bug reports, patches, and anything that +may be helpful to the project. + +The git source code repository can be found on Gitorious at +@url{https://gitorious.org/sly/sly}. @node Copying This Manual @appendix Copying This Manual @@ -81,7 +183,9 @@ The document was typeset with @node Index @unnumbered Index -@printindex cp +@syncodeindex tp fn +@syncodeindex vr fn +@printindex fn @bye |