
SGE Fundamentals
****************


Contents
^^^^^^^^

* SGE Fundamentals

  * SGE Concepts

    * Events

    * Position

    * Z-Axis

    * The Game Loop

  * Global Variables and Constants

  * Information specific to the Pygame SGE

    * License

    * Dependencies

    * Formats Support

    * Missing Features

    * Known Problems

      * Keyboard Lock-up

      * Saving PNG Images

The SGE Game Engine ("SGE", pronounced like "Sage") is a general-
purpose 2-D game engine.  It takes care of several details for you so
you can focus on the game itself.  This makes more rapid game
development possible, and it also makes the SGE easy to learn.

The SGE is libre software, and the SGE documentation (including all
docstrings) is released to the public domain via CC0.

Although it isn't required, you are encouraged to release your games'
code under a libre software license, such as the GNU General Public
License, the Expat License, or the Apache License.  Doing so is easy,
does not negatively affect you, and is highly appreciated as a
contribution to a free society.


SGE Concepts
============


Events
------

The SGE uses an event-based system.  When an event occurs, a certain
event method (with a name that begins with "event_") is called. To
define actions triggered by events, simply override the appropriate
event method.

At a lower level, it is possible to read "input events" from
"sge.game.input_events" and handle them manually.  See the
documentation for "sge.input" for more information.  This is not
recommended, however, unless you are running your own loop for some
reason (in which case it is necessary to do this in order to get input
from the user).


Position
--------

In all cases of positioning for the SGE, it is based on a two-
dimensional graph with each unit being a pixel.  This graph is not
quite like regular graphs.  The horizontal direction, normally called
"x", is the same as the x-axis on a regular graph; "0" is the origin,
positive numbers are to the right of the origin, and negative numbers
are to the left of the origin.  However, in the vertical direction,
normally called "y", "0" is the origin, positive numbers are below the
origin, and negative numbers are above the origin.  While slightly
jarring if you are used to normal graphs, this is in fact common in
2-D game development and is also how pixels in most image formats are
indexed.

Except where otherwise specified, the origin is always located at the
top-leftmost position of an object.

In addition to integers, position variables are allowed by the SGE to
be floating-point numbers.


Z-Axis
------

The SGE uses a Z-axis to determine where objects are placed in the
third dimension.  Objects with a higher Z value are considered to be
closer to the viewer and thus will be placed over objects which have a
lower Z value.  Note that the Z-axis does not allow 3-D gameplay or
effects; it is only used to tell the SGE what to do with objects that
overlap.  For example, if an object called "spam" has a Z value of "5"
while an object called "eggs" has a Z value of "2", "spam" will
obscure part or all of "eggs" when the two objects overlap.

If two objects with the same Z-axis value overlap, the object which
was most recently added to the room is placed in front.


The Game Loop
-------------

There can occasionally be times where you want to run your own loop,
independent of the SGE's main loop.  This is not recommended in
general, but if you must (to freeze the game, for example), you should
know the general game loop structure:

   while True:
       # Input events
       sge.game.pump_input()
       while sge.game.input_events:
           event = sge.game.input_events.pop(0)

           # Handle event

       # Regulate speed
       time_passed = sge.game.regulate_speed()

       # Logic (e.g. collision detection and step events)

       # Refresh
       sge.game.refresh()

"sge.dsp.Game.pump_input()" should be called every frame regardless of
whether or not user input is needed.  Failing to call it will cause
the queue to build up, but more importantly, the OS may decide that
the program has locked up if it doesn't get a response for a long
time.

"sge.dsp.Game.regulate_speed()" limits the frame rate of the game and
tells you how much time has passed since the last frame.  It is not
technically necessary, but using it is highly recommended; otherwise,
the CPU will be working harder than it needs to and if things are
moving, their speed will be irregular.

"sge.dsp.Game.refresh()" is necessary for any changes to the screen to
be seen by the user.  This includes new objects, removed objects, new
projections, discontinued projections, etc.


Global Variables and Constants
==============================

sge.IMPLEMENTATION

   A string indicating the name of the SGE implementation.

sge.SCALE_METHODS

   A list of specific scale methods supported by the SGE
   implementation.

   Note: This list does not include the generic scale methods,
     ""noblur"" and ""smooth"".  It is also possible for this list to
     be empty.

sge.BLEND_NORMAL

   Flag indicating normal blending.

sge.BLEND_RGBA_ADD

   Flag indicating RGBA Addition blending: the red, green, blue, and
   alpha color values of the source are added to the respective color
   values of the destination, to a maximum of 255.

sge.BLEND_RGBA_SUBTRACT

   Flag indicating RGBA Subtract blending: the red, green, blue, and
   alpha color values of the source are subtracted from the respective
   color values of the destination, to a minimum of 0.

sge.BLEND_RGBA_MULTIPLY

   Flag indicating RGBA Multiply blending: the red, green, blue, and
   alpha color values of the source and destination are converted to
   values between 0 and 1 (divided by 255), the resulting destination
   color values are multiplied by the respective resulting source
   color values, and these results are converted back into values
   between 0 and 255 (multiplied by 255).

sge.BLEND_RGBA_SCREEN

   Flag indicating RGBA Screen blending: the red, green, blue, and
   alpha color values of the source and destination are inverted
   (subtracted from 255) and converted to values between 0 and 1
   (divided by 255), the resulting destination color values are
   multiplied by the respective resulting source color values, and
   these results are converted back into values between 0 and 255
   (multiplied by 255) and inverted again (subtracted from 255).

sge.BLEND_RGBA_MINIMUM

   Flag indicating RGBA Minimum (Darken Only) blending: the smallest
   respective red, green, blue, and alpha color values out of the
   source and destination are used.

sge.BLEND_RGBA_MAXIMUM

   Flag indicating RGBA Maximum (Lighten Only) blending: the largest
   respective red, green, blue, and alpha color values out of the
   source and destination are used.

sge.BLEND_RGB_ADD

   Flag indicating RGB Addition blending: the same thing as RGBA
   Addition blending (see "sge.BLEND_RGBA_ADD") except the
   destination's alpha values are not changed.

sge.BLEND_RGB_SUBTRACT

   Flag indicating RGB Subtract blending: the same thing as RGBA
   Subtract blending (see "sge.BLEND_RGBA_SUBTRACT") except the
   destination's alpha values are not changed.

sge.BLEND_RGB_MULTIPLY

   Flag indicating RGB Multiply blending: the same thing as RGBA
   Multiply blending (see "sge.BLEND_RGBA_MULTIPLY") except the
   destination's alpha values are not changed.

sge.BLEND_RGB_SCREEN

   Flag indicating RGB Screen blending: the same thing as RGBA Screen
   blending (see "sge.BLEND_RGBA_SCREEN") except the destination's
   alpha values are not changed.

sge.BLEND_RGB_MINIMUM

   Flag indicating RGB Minimum (Darken Only) blending: the same thing
   as RGBA Minimum blending (see "sge.BLEND_RGBA_MINIMUM") except the
   destination's alpha values are not changed.

sge.BLEND_RGB_MAXIMUM

   Flag indicating RGB Maximum (Lighten Only) blending: the same thing
   as RGBA Maximum blending (see "sge.BLEND_RGBA_MAXIMUM") except the
   destination's alpha values are not changed.

sge.game

   Stores the current "sge.dsp.Game" object.  If there is no
   "sge.dsp.Game" object currently, this variable is set to "None".


Information specific to the Pygame SGE
======================================


License
-------

The Pygame SGE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

The Pygame SGE is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with the Pygame SGE.  If not, see
<http://www.gnu.org/licenses/>.


Dependencies
------------

* Python 2 (2.7 or later) or 3 (3.1 or later)
  <http://www.python.org>

* Pygame 1.9.1 or later <http://pygame.org>


Formats Support
---------------

"sge.gfx.Sprite" supports the following image formats:

* PNG

* JPEG

* Non-animated GIF

* BMP

* PCX

* Uncompressed Truevision TGA

* TIFF

* ILBM

* Netpbm

* X Pixmap

If Pygame is built without full image support, "sge.gfx.Sprite" will
only be able to load uncompressed BMP images.

"sge.snd.Sound" supports the following audio formats:

* Uncompressed WAV

* Ogg Vorbis

"sge.snd.Music" supports the following audio formats:

* Ogg Vorbis

* MOD

* XM

* MIDI

MP3 is also supported on some systems, but not all, due to software
idea patents which restrict use of this format.  On some systems,
attempting to load an unsupported format can crash the game.  Since
MP3 support is not available on all systems, it is best to avoid using
it; consider using Ogg Vorbis instead.

For starting position in MOD files, the pattern order number is used
instead of the number of milliseconds.

The pygame.mixer module, which is used for all audio playback, is
optional and depends on SDL_mixer; if pygame.mixer is unavailable,
sounds and music will not play.


Missing Features
----------------

"sge.gfx.Sprite.draw_line()", "sge.dsp.Room.project_line()", and
"sge.dsp.Game.project_line()" support anti-aliasing for lines with a
thickness of 1 only.  "sge.gfx.Sprite.draw_polygon()",
"sge.dsp.Room.project_polygon()", and "sge.dsp.Game.project_polygon()"
support anti-aliasing for outlines of polygons with a thickness of 1
only. "sge.gfx.Sprite.draw_text()", "sge.dsp.Room.project_text()", and
"sge.dsp.Game.project_text()" support anti-aliasing in all cases.  No
other drawing or projecting methods support anti-aliasing.


Known Problems
--------------

Since the Pygame SGE uses Pygame, it necessarily inherits Pygame's
bugs. Below, some notable bugs in Pygame 1.9.1 (the latest Pygame
release) are indicated.


Keyboard Lock-up
~~~~~~~~~~~~~~~~

There is a bug in either Pygame or SDL, most likely SDL, which
sometimes causes keyboard input to stop working.  In Pygame programs
such as this one, this occurs when pygame.display.set_mode is called
multiple times, which in the Pygame SGE occurs any time either the
size of the window or the video mode (windowed or fullscreen) changes.
See this post from the SGE blog for more information:

https://savannah.nongnu.org/forum/forum.php?forum_id=8113

You may also be interested in this report on the Pygame issue tracker:

https://bitbucket.org/pygame/pygame/issue/212/

As mentioned in the post on the SGE blog, this is a particularly
serious problem for anyone using the X Window System (e.g. pretty much
any GNU/Linux user), or any other window system that gives complete
control to fullscreen SDL applications.  On these systems, if the game
requires keyboard input to either leave fullscreen or exit, the system
will become unresponsive to everything that isn't sent directly to the
kernel (such as the magic SysRq key in Linux systems).

Luckily, the bug doesn't seem to affect mouse input, so if you allow
the player to enter fullscreen mode in-game, it is highly recommended
for you to provide some method of either exiting the game or exiting
fullscreen with the mouse.  This can be a button somewhere on the
screen if the game uses the mouse cursor, or it can be a simple mouse
button click otherwise.


Saving PNG Images
~~~~~~~~~~~~~~~~~

Some versions of Pygame have problems saving color information of PNG
images correctly.  As a result, depending on your exact version of
Pygame, images saves with "sge.gfx.Sprite.save()" may be discolored.
The best workaround is to choose a different format, such as BMP, GIF,
or JPEG.
