Basic Games with Python

About this class

Walk through basics of writing a game:

Along the way write a fun toy in 20-30 lines of Python code.

Pyglet

Gaming libraries:

Pyglet is slightly more modern, Pygame more widely used.

We’re using Pyglet

Installation

Working with pre-release version. Fixes some bugs that bit me on MacOS

$ virtualenv MYGAME
$ source MYGAME/bin/activate
(MYGAME) $ pip install --upgrade http://pyglet.googlecode.com/archive/tip.zip

Basic Pyglet

Using the Pyglet API

hello_world.py
import pyglet

window = pyglet.window.Window()
#pyglet.app.run()

You can read about the Window Class in the Pyglet docs.

Pyglet handles making a UI window, sizing it, handles OS events like "Close" button.

Try it out!

Basic Python - if a little magical

Frameworks always lead to "weird" code because you’re not exactly in charge. But pyglet does a pretty good job of helping you structure your code.

pyglet.window.Window() is a class. Instanciating it makes a window show up.

pyglet.app.run() starts a program that you didn’t write.

What happens if you comment out the pyglet.app.run() line?

Event Loops

Event loops are common in many kinds of programming - from network to UI - where what your program does is sit there, waiting for events happen.

Handling Events

hello_world2.py
import pyglet

window = pyglet.window.Window()
label = pyglet.text.Label('Hello, world', x=window.width//2, y=window.height//2,
                          anchor_x='center', anchor_y='center')

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

pyglet.app.run()

Pyglet generally has us handle events by providing an event handler.

Event handler is just a function that registers in some way that it wants to be called when something happens.

hello_world2.py
import pyglet

window = pyglet.window.Window()
label = pyglet.text.Label('Hello, world', x=window.width//2, y=window.height//2,
                          anchor_x='center', anchor_y='center')

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

pyglet.app.run()

on_draw

Game frameworks all do more or less the same thing when used naively - every few milliseconds redraw the screen. This is the Application Loop or Game Loop.

Animation comes from moving things around.

The on_draw event is your simples access to Pyglet’s Application Loop. Let’s add some animation

Animation

hello_world3.py
import pyglet

window = pyglet.window.Window()
label = pyglet.text.Label('Hello, world', x=window.width//2, y=window.height//2,
                          anchor_x='center', anchor_y='center')

@window.event
def on_draw():
  window.clear()
  label.x += 1
  label.y += 1
  label.draw()

pyglet.app.run()

Does it work? (Hit the space bar)

the on_draw event is only called if there’s something to do.

And if no events have happened, then nothing has changed, and there’s nothing to do!

We need to cause an event on a regular basis.

Animation and Timers

hello_world4.py
import pyglet

window = pyglet.window.Window()
label = pyglet.text.Label('Hello, world', x=window.width//2, y=window.height//2,
                          anchor_x='center', anchor_y='center')

def update(dt):
  print(dt) # time elapsed since last time we were called
  label.x += 1
  label.y += 1

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

pyglet.clock.schedule(update) # cause a timed event as fast as you can!
pyglet.app.run()

Use pyglet.clock.schedule(func) or pyglet.clock.schedule_interval(func, seconds) to schedule timed events.

Quiz Time

We’re using x and y coordinates. What are the numbers and what do they mean?

x is the horizontal axix, y is the vertical axis.

The bottom left corner is (x=0, y=0). The unit is pixels.

Oh and by default most things are placed by their bottom left corner. Hence the configuration:

label = pyglet.text.Label('Hello, world', x=window.width//2, y=window.height//2,
                          anchor_x='center', anchor_y='center')

Media

Pyglet lets us show images easily!

image.py
import pyglet

window = pyglet.window.Window()
image = pyglet.resource.image('simeon64x64.jpg')
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2

@window.event
def on_draw():
  window.clear()
  image.blit(window.width//2, window.height//2)

pyglet.app.run()

Although if you have a lot of images see http://www.pyglet.org/doc/programming_guide/displaying_images.html <<<

Pyglet lets us play sounds

sounds.py
import pyglet

window = pyglet.window.Window()
explosion = pyglet.resource.media('explosion.wav', streaming=False)

def boom(dt):
    explosion.play()

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

pyglet.clock.schedule_interval(boom, 1) # Explode every 1 seconds
pyglet.app.run()

See http://www.bfxr.net/ for your own 8bit game sounds.

More Events

We want to do more than draw the window and cause timed events. You can’t have a game without user input!

It’s easy in pyglet to handle discrete mouse and keyboard events. Try holding down on the arrow keys in this demo however…

events.py
import pyglet

from pyglet.window import key, mouse

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

position = dict(x=0, y=0)

@window.event
def on_key_press(symbol, modifiers):
  if symbol == key.RIGHT:
    position['x'] += 1
  elif symbol == key.UP:
    position['y'] += 1
  elif symbol == key.DOWN:
    position['y'] -= 1
  elif symbol == key.LEFT:
    position['x'] -= 1

@window.event
def on_mouse_press(x, y, button, modifiers):
  if button == mouse.LEFT:
    position['x'] = x
    position['y'] = y

@window.event
def on_draw():
  window.clear()
  image.blit(position['x'], position['y'])

pyglet.app.run()

Are you ready to write some code?

Let’s see:

Project

I’d like replicate a game from my childhood.

Funnels and Buckets taught me to type math facts fast on a 10key keypad.

It was released in 1984 (I know, I’m getting old).

The game at its simplest is

See http://youtu.be/mfnV47vLsmk?t=24s for gameplay

Plan

  1. Identify all the game pieces that will be displayed (math fact, answer box, score box, etc)

  2. Create objects to represent them and draw them on the screen. Use timed events to update the drawn objects.

  3. Use globals to store state (what math fact?, what is the answer? What is the score?)

You may find that you have more code in your problem domain than in your game domain. How do you generate the math problems and calculate the correct answer?

I’m going to look at http://en.wikipedia.org/wiki/Spaced_repetition and see if I can optimize the math problems shown so that difficult problem re-occur but not too soon!

/

#