doc: Expand and improve Kernel manual section.
authorDavid Thompson <dthompson2@worcester.edu>
Wed, 8 Apr 2020 12:59:11 +0000 (08:59 -0400)
committerDavid Thompson <dthompson2@worcester.edu>
Wed, 8 Apr 2020 12:59:39 +0000 (08:59 -0400)
doc/api.texi

index 18e0841..f553f25 100644 (file)
@@ -9,78 +9,29 @@
 @node Kernel
 @section Kernel
 
-At the very core of Chickadee, in the @code{(chickadee game-loop)}
-module, lies an event loop.  This loop, or ``kernel'', is responsible
-for ensuring that the game is updated at the desired interval,
-rendering the current state of the game world, and handling errors if
-they occur.  The kernel implements what is known as a ``fixed
-timestep'' game loop, meaning that the game simulation will be
-advanced by a fixed interval of time and will never vary from frame to
-frame, unlike some other styles of game loops.  The appropriately
-named @code{run-game*} and @code{abort-game} procedures are the entry
-and exit points to the Chickadee game loop kernel.
-
-On its own, the kernel does not do very much at all.  In order to
-actually respond to input events, update game state, or render output,
-the programmer must provide an engine.  But don't worry, you don't
-have to start from scratch!  Chickadee comes with a simple engine that
-uses SDL to create a graphical window and handle input devices, and
-OpenGL to handle rendering.  This default engine is enough for most
-users to get started writing games quickly.  More advanced users may
-want to write a custom engine that uses a different I/O system.
-Perhaps you are writing a text adventure or roguelike that reads from
-and writes to a terminal instead of a graphical window.  The game loop
-kernel makes no assumptions.
+This section of the manual covers the foundation of Chickadee: The
+game loop and desktop environment interaction.
 
-@deffn {Procedure} run-game* [#:update] [#:render] [#:time] [#:error] @
-       [#:update-hz 60]
-
-Start the game loop.  This procedure will not return until
-@code{abort-game} is called.
-
-The core game loop is generic and requires four additional procedures
-to operate:
-
-@itemize
-@item
-@var{update}: Called @var{update-hz} times per second to advance the
-game simulation.  This procedure is called with a single argument: The
-amount of time that has passed since the last update, in milliseconds.
-@item
-@var{render}: Called each iteration of the loop to render the game to
-the desired output device.  This procedure is called with a single
-argument: A value in the range [0, 1] which represents how much time
-has past since the last game state update relative to the upcoming
-game state update, as a percentage.  Because the game state is updated
-independent of rendering, it is often the case that rendering is
-occuring between two updates.  If the game is rendered as it was
-during the last update, a strange side-effect will occur that makes
-animation appear rough or ``choppy''.  To counter this, the
-@var{alpha} value can be used to perfrom a linear interpolation of a
-moving object between its current position and its previous position.
-This odd trick has the pleasing result of making the animation look
-smooth again, but requires keeping track of previous state.
-@item
-@var{time}: Called to get the current time in milliseconds.  This
-procedure is called with no arguments.
-@item
-@var{error}: Called when an error from the @var{update} or
-@var{render} procedures reaches the game loop.  This procedure is
-called with three arguments: The call stack, the error key, and the
-error arguments.  If no error handler is provided, the default
-behavior is to simply re-throw the error.
-@end itemize
-
-@end deffn
+@menu
+* The Game Loop::               The core event loop.
+* Input Devices::               Mouse, keyboard, controller input.
+* Window Manipulation::         Inspect and modify the graphical window.
+* Live Coding::                 Tips for building games from the REPL.
+@end menu
 
-@deffn {Procedure} abort-game
-Stop the currently running Chickadee game loop.
-@end deffn
+@node The Game Loop
+@subsection The Game Loop
 
-Since most users will want to write 2D/3D games with hardware
-accelerated graphics rendering, controlled via keyboard, mouse, or
-game controller, Chickadee comes with an easy to use engine just for
-this purpose in the @code{(chickadee)} module: @code{run-game}.
+At the very core of Chickadee there is an event loop.  This loop, or
+``kernel'', is responsible for ensuring that the game is updated at
+the desired interval, handling input devices, rendering the current
+state of the game world, and handling errors if they occur.  The
+kernel implements what is known as a ``fixed timestep'' game loop,
+meaning that the game simulation will be advanced by a fixed interval
+of time and will never vary from frame to frame, unlike some other
+styles of game loops.  The appropriately named @code{run-game} and
+@code{abort-game} procedures are the entry and exit points to the
+Chickadee game loop.
 
 @deffn {Procedure} run-game [#:window-title "Chickadee!"] @
        [#:window-width 640] [#:window-height 480] @
@@ -91,7 +42,7 @@ this purpose in the @code{(chickadee)} module: @code{run-game}.
        [#:controller-add] [#:controller-remove] [#:controller-press] @
        [#:controller-release] [#:controller-move] [#:error]
 
-Run the Chickadee game loop using the SDL engine in OpenGL mode.
+Run the Chickadee game loop.
 
 A new graphical window will be opened with @var{window-width} x
 @var{window-height} as its dimensions, @var{window-title} as its
@@ -351,6 +302,206 @@ The default behavior is to re-throw the error.
 
 @end deffn
 
+To stop the game loop, simply call @code{abort-game}.
+
+@deffn {Procedure} abort-game
+Stop the currently running Chickadee game loop.
+@end deffn
+
+The above explanation of the game loop was partially a lie.  It's true
+that there is a game loop at the center of Chickadee, but
+@code{run-game} is not it's true entry point.  There exists an even
+lower level procedure, @code{run-game*}, in the @code{(chickadee
+game-loop)} module that @code{run-game} uses under the hood.
+
+On its own, @code{run-game*} does not do very much at all.  In order
+to actually respond to input events, update game state, or render
+output, the developer must provide an engine.  @code{run-game} is such
+an engine, and it's likely all a developer will need.  However, what
+if a developer wanted to use all of the useful Chickadee features to
+make a terminal roguelike game instead?  Chickadee doesn't come with a
+terminal rendering engine, but the developer could write one without
+having to write their own core game loop.
+
+@deffn {Procedure} run-game* [#:update] [#:render] [#:time] [#:error] @
+       [#:update-hz 60]
+
+Start the game loop.  This procedure will not return until
+@code{abort-game} is called.
+
+The core game loop is generic and requires four additional procedures
+to operate:
+
+@itemize
+@item
+@var{update}: Called @var{update-hz} times per second to advance the
+game simulation.  This procedure is called with a single argument: The
+amount of time that has passed since the last update, in milliseconds.
+@item
+@var{render}: Called each iteration of the loop to render the game to
+the desired output device.  This procedure is called with a single
+argument: A value in the range [0, 1] which represents how much time
+has past since the last game state update relative to the upcoming
+game state update, as a percentage.  Because the game state is updated
+independent of rendering, it is often the case that rendering is
+occuring between two updates.  If the game is rendered as it was
+during the last update, a strange side-effect will occur that makes
+animation appear rough or ``choppy''.  To counter this, the
+@var{alpha} value can be used to perfrom a linear interpolation of a
+moving object between its current position and its previous position.
+This odd trick has the pleasing result of making the animation look
+smooth again, but requires keeping track of previous state.
+@item
+@var{time}: Called to get the current time in milliseconds.  This
+procedure is called with no arguments.
+@item
+@var{error}: Called when an error from the @var{update} or
+@var{render} procedures reaches the game loop.  This procedure is
+called with three arguments: The call stack, the error key, and the
+error arguments.  If no error handler is provided, the default
+behavior is to simply re-throw the error.
+@end itemize
+
+@end deffn
+
+@node Input Devices
+@subsection Input Devices
+
+While @code{run-game} provides hooks for mouse/keyboard/controller
+input events, it is often necessary to query input devices for their
+current state.  For example, it could be desirable to query the state
+of the arrow keys every time the update hook is called to determine
+which direction the player should move that frame.
+
+@deffn {Procedure} key-pressed? key
+Return @code{#t} if @var{key} is currently being pressed.
+@end deffn
+
+@deffn {Procedure} key-released? key
+Return @code{#t} if @var{key} is @emph{not} currently being pressed.
+@end deffn
+
+@deffn {Procedure} mouse-x
+Return the current X coordinate of the mouse cursor.
+@end deffn
+
+@deffn {Procedure} mouse-y
+Return the current Y coordinate of the mouse cursor.
+@end deffn
+
+@deffn {Procedure} mouse-button-pressed? button
+Return @code{#t} if @var{button} is currently being pressed.
+@end deffn
+
+@deffn {Procedure} mouse-button-released? button
+Return @code{#t} if @var{button} is @emph{not} currently being
+pressed.
+@end deffn
+
+@deffn {Procedure} controller-axis controller axis
+Return a floating point value in the range [-1, 1] corresponding to
+how much @var{axis} (an analog stick or trigger) is being pushed on
+@var{controller}.  0 is returned if @var{axis} is not being pushed at
+all.
+@end deffn
+
+@deffn {Procedure} controller-name controller
+Return the name of @var{controller}.
+@end deffn
+
+@deffn {Procedure} controller-button-pressed? controller button
+Return @code{#t} if @var{button} on @var{controller} is currently
+being pressed.
+@end deffn
+
+@deffn {Procedure} controller-button-released? controller button
+Return @code{#t} if @var{button} on @var{controller} is @emph{not}
+currently being pressed.
+@end deffn
+
+@node Window Manipulation
+@subsection Window Manipulation
+
+@deffn {Procedure} current-window
+Return the currently active game window.
+@end deffn
+
+@deffn {Procedure} window? obj
+Return @code{#t} if @var{obj} is a window object.
+@end deffn
+
+@deffn {Procedure} window-title window
+Return the title of @var{window}.
+@end deffn
+
+@deffn {Procedure} window-width window
+Return the width of @var{window} in pixels.
+@end deffn
+
+@deffn {Procedure} window-height window
+Return the height of @var{window} in pixels.
+@end deffn
+
+@deffn {Procedure} window-x window
+Retun the X coordinate of the upper-left corner of @var{window}.
+@end deffn
+
+@deffn {Procedure} window-y window
+Return the Y coordinate of the upper-left corner of @var{window}.
+@end deffn
+
+@deffn {Procedure} hide-window! window
+Hide @var{window}.
+@end deffn
+
+@deffn {Procedure} show-window! window
+Show @var{window}.
+@end deffn
+
+@deffn {Procedure} maximize-window! window
+Maximize @var{window}.
+@end deffn
+
+@deffn {Procedure} minimize-window! window
+Minimize @var{window}.
+@end deffn
+
+@deffn {Procedure} raise-window! window
+Make @var{window} visible over all other windows.
+@end deffn
+
+@deffn {Procedure} restore-window! window
+Restore the size and position of a minimized or maximized
+@var{window}.
+@end deffn
+
+@deffn {Procedure} set-window-border! window border?
+Enable/disable the border around @var{window}.  If @var{border?} is
+@code{#f}, the border is disabled, otherwise it is enabled.
+@end deffn
+
+@deffn {Procedure} set-window-title! window title
+Change the title of @var{window} to @var{title}.
+@end deffn
+
+@deffn {Procedure} set-window-size! window width height
+Change the dimensions of @var{window} to @var{width} x @var{height}
+pixels.
+@end deffn
+
+@deffn {Procedure} set-window-position! window x y
+Move the upper-left corner of @var{window} to pixel coordinates
+(@var{x}, @var{y}).
+@end deffn
+
+@deffn {Procedure} set-window-fullscreen! window fullscreen?
+Enable or disable fullscreen mode for @var{window}.  If
+@var{fullscreen?} is @code{#f}, fullscreen mode is disabled, otherwise
+it is enabled.
+@end deffn
+
+
+@node Live Coding
 @subsection Live Coding
 
 One of the biggest appeals of any Lisp dialect is the ability to use
@@ -363,18 +514,22 @@ fairly easy to hook up a special kind of REPL yourself.
 
 First, create a cooperative REPL server (It's important to use Guile's
 cooperative REPL server instead of the standard REPL server in
-@code{(system repl server)} to avoid thread synchronization issues):
+@code{(system repl server)} to avoid thread synchronization issues).
+Then, in the game loop's update procedure, call
+@code{poll-coop-repl-server} and pass the REPL object.  Here is a
+template to follow:
 
 @example
-(use-modules (system repl coop-server))
+(use-modules (chickadee)
+             (system repl coop-server))
 
 (define repl (spawn-coop-repl-server))
-@end example
 
-Then, in the game loop's update procedure, add this:
+(define (update dt)
+  (poll-coop-repl-server repl)
+  ...)
 
-@example
-(poll-coop-repl-server repl)
+(run-game #:update update ...)
 @end example
 
 To use the REPL, connect to it via port 37146.  Telnet will do the
@@ -382,8 +537,6 @@ trick, but using the @uref{https://www.nongnu.org/geiser/, Geiser}
 extension for Emacs is by far the best way to develop at the REPL with
 Guile.  Use @code{M-x connect-to-guile} to connect to the REPL server.
 
-Happy hacking!
-
 @node Math
 @section Math