Writing a pyglet application
============================

Getting started with a new library or framework can be daunting, especially
when presented with a large amount of reference material to read.  This
chapter gives a very quick introduction to pyglet without covering any of the
details.

.. contents::
    :local:

Hello, World
------------

We'll begin with the requisite "Hello, World" introduction.  This program will
open a window with some text in it and wait to be closed.  You can find the
entire program in the `examples/programming_guide/hello_world.py` file.

Begin by importing the pyglet package::

    import pyglet

Create a `Window` by calling its default constructor.  The window will be
visible as soon as it's created, and will have reasonable default values for
all its parameters::

    window = pyglet.window.Window()

To display the text, we'll create a `Label`.  Keyword arguments are used
to set the font, position and anchorage of the label::

    label = pyglet.text.Label('Hello, world', 
                              font_name='Times New Roman', 
                              font_size=36,
                              x=window.width//2, y=window.height//2,
                              anchor_x='center', anchor_y='center')

An `on_draw` event is dispatched to the window to give it a chance to redraw
its contents.  pyglet provides several ways to attach event handlers to
objects; a simple way is to use a decorator::

    @window.event
    def on_draw():
        window.clear()
        label.draw()

Within the ``on_draw`` handler the window is cleared to the default background
color (black), and the label is drawn.

Finally, call::

    pyglet.app.run()

To let pyglet respond to application events such as the mouse and keyboard.
Your event handlers will now be called as required, and the `run` method will
return only when all application windows have been closed.

Note that earlier versions of pyglet required the application developer to
write their own event-handling runloop.  This is still possible, but
discouraged; see `The application event loop` for details.

Image viewer
------------

Most games will need to load and display images on the screen.  In this
example we'll load an image from the application's directory and display it
within the window::

    import pyglet

    window = pyglet.window.Window()
    image = pyglet.resource.image('kitten.jpg')

    @window.event
    def on_draw():
        window.clear()
        image.blit(0, 0)

    pyglet.app.run()

We used the `pyglet.resource.image` function to load the image, which
automatically locates the file relative to the source file (rather than the
working directory).  To load an image not bundled with the application (for
example, specified on the command line, you would use `pyglet.image.load`).

The `AbstractImage.blit` method draws the image.  The arguments ``(0, 0)``
tell pyglet to draw the image at pixel coordinates 0, 0 in the window
(the lower-left corner).

The complete code for this example is located in
`examples/programming_guide/image_viewer.py`.

Handling mouse and keyboard events
----------------------------------

So far the only event used is the `on_draw` event.  To react to keyboard and
mouse events, it's necessary to write and attach event handlers for these
events as well::

    import pyglet

    window = pyglet.window.Window()

    @window.event
    def on_key_press(symbol, modifiers):
        print 'A key was pressed'

    @window.event
    def on_draw():
        window.clear()

    pyglet.app.run()

Keyboard events have two parameters: the virtual key `symbol` that was
pressed, and a bitwise combination of any `modifiers` that are present (for
example, the ``CTRL`` and ``SHIFT`` keys).

The key symbols are defined in `pyglet.window.key`::

    from pyglet.window import key

    @window.event
    def on_key_press(symbol, modifiers):
        if symbol == key.A:
            print 'The "A" key was pressed.'
        elif symbol == key.LEFT:
            print 'The left arrow key was pressed.'
        elif symbol == key.ENTER:
            print 'The enter key was pressed.'

See the `pyglet.window.key` documentation for a complete list of key symbols.

Mouse events are handled in a similar way::

    from pyglet.window import mouse

    @window.event
    def on_mouse_press(x, y, button, modifiers):
        if button == mouse.LEFT:
            print 'The left mouse button was pressed.'

The ``x`` and ``y`` parameters give the position of the mouse when the button
was pressed, relative to the lower-left corner of the window.

There are more than 20 event types that you can handle on a window.  The
easiest way to find the event name and parameters you need is to add the
following line to your program::

    window.push_handlers(pyglet.window.event.WindowEventLogger())

This will cause all events received on the window to be printed to the
console.

An example program using keyboard and mouse events is in
`examples/programming_guide/events.py`

Playing sounds and music
------------------------

pyglet makes it easy to play and mix multiple sounds together in your game.
The following example plays an MP3 file [#mp3]_::

    import pyglet

    music = pyglet.resource.media('music.mp3')
    music.play()

    pyglet.app.run()

As with the image loading example presented earlier, `pyglet.resource.media`
locates the sound file in the application's directory (not the working
directory).  If you know the actual filesystem path (either relative or
absolute), use `pyglet.media.load`.

Short sounds, such as a gunfire shot used in a game, should be decoded in
memory before they are used, so that they play more immediately and incur less
of a CPU performance penalty.  Specify ``streaming=False`` in this case::

    sound = pyglet.resource.media('shot.wav', streaming=False)
    sound.play()

The `examples/media_player.py` example demonstrates playback of streaming
audio and video using pyglet.  The `examples/noisy/noisy.py` example
demonstrates playing many short audio samples simultaneously, as in a game.

.. [#mp3] MP3 and other compressed audio formats require AVbin to be installed
          (this is the default for the Windows and Mac OS X installers).
          Uncompressed WAV files can be played without AVbin.

Where to next?
--------------

The examples presented in this chapter should have given you enough
information to get started writing simple arcade and point-and-click-based
games.

The remainder of this programming guide goes into quite technical detail
regarding some of pyglet's features.  While getting started, it's recommended
that you skim the beginning of each chapter but not attempt to read through
the entire guide from start to finish.

To write 3D applications or achieve optimal performance in your 2D
applications you'll need to work with OpenGL directly.  The canonical
references for OpenGL are `The OpenGL Programming Guide`_ and 
`The OpenGL Shading Language`_.

There are numerous examples of pyglet applications in the ``examples/``
directory of the documentation and source distributions.  Keep checking
http://www.pyglet.org/ for more examples and tutorials as they are written.

.. _The OpenGL Programming Guide: http://opengl.org/documentation/books/#the_opengl_programming_guide_the_official_guide_to_learning_opengl_version
.. _The OpenGL Shading Language: http://opengl.org/documentation/books/#the_opengl_shading_language_2nd_edition
