Game development HOWTO
This HOWTO is current as of July 2007. Rapid changes are occurring; expect things to change.
Note: The Pygame wrapper requires at least build 432 to work. See the reference manual at Pygame wrapper. See also Game development.
Crash Course on Pygame
The slides from Noah's lecture at the start of the game jam are online at http://dev.laptop.org/~coderanger/ (both PDF and PowerPoint form).
Development Environment
Start with Pygame. If you are running Mac OS X, check out the Mac setup instructions.
You don't need a laptop for simple Pygame development. When creating your Pygame game, use this new boilerplate:
import sys import pygame from pygame.locals import * def main(): window = pygame.display.set_mode((400, 225)) pygame.event.set_blocked(MOUSEMOTION) pygame.init() while True: # event = pygame.event.wait() for event in [ pygame.event.wait() ] + pygame.event.get( ): print event if event.type == KEYUP: # Quit on 'q' if event.key == 113: sys.exit(0) if __name__=="__main__": main()
The 'main' method will be called by the activity wrapper later on, so it must be called 'main'. Using pygame.event.wait() instead of pygame.event.get() reduces the cpu-load from 99% to 0.7 - 4%.
Wrapping and Testing
If you want to test using laptop software, but you don't have a real XO, you could set up an emulated environment.
To make your game run as an Activity, you will need the 'olpcgames' wrapper, otherwise known simply as "the wrapper". Eventually, the wrapper will be included as part of the standard laptop software distribution, but for now you must include it in your Activity.
git clone git://dev.laptop.org/projects/games-misc
This will download several games-related projects. There are a few game Activities checked in, as well as the wrapper.
First construct an activity development bundle as in Sugar Activity Tutorial.
The wrapper requires the following boilerplate as the main class of your activity as specified in activity.info. Generally this is called 'activity.py' and your Pygame app retains its original name:
import olpcgames # Class name must match 'class' property in activity/activity.info: class ExampleActivity(olpcgames.PyGameActivity): """An example of using a Pygame game as a Sugar activity.""" game_name = 'examplemodule:main' # game_name must match name of your Pygame module game_title = 'Example' game_size = (1200,825)
The game_name
parameter has the format "module:method". The module will be imported and the method called to start your Pygame application. Method is optional and defaults to main
. (FIXME: Use Gettext to localize the game_title parameter.)
The game_size is what sets the display mode in Pygame.
The last step: you need to copy or link the 'olpcgames' directory from the Git repository you checked out into the root of your Activity. (Eventually, 'olpcgames' will be part of the main laptop build, so you will no longer need to do this.)
Hardware
The Pygame page has some information on hardware.
Camera
The camera works sorta using the wrapper. Support will be improved in the future.
import olpcgames
Whenever you need a camera, just do:
img = olpcgames.camera.snap()
This blocks your game until the camera returns a picture, then returns it as a Pygame surface. (note: test how long it tends to take)
Sharing and the Mesh
Your activity can automatically be shared (through the user clicking "Share" on the Sugar toolbar). You should be using build >=530 (or so) for mesh related stuff. When the user does this, your activity will appear in the Neighborhood screen and others can join it.
In order to meaningfully communicate, you must
import olpcgames.mesh as mesh
Now, you can make use of events you receive that are mesh related. See Pygame_wrapper#Mesh for details.
Here is a simple example -- in your event loop, just add listening for certain mesh events:
for evt in pygame.event.get(): if evt.type == pygame.KEYDOWN: # ... elif evt.type == mesh.PARTICIPANT_ADD: # Somebody joined. Add them to our list of people, and send them a message: self.participants.append(evt.handle) mesh.send_to(evt.handle, str(self.game_state)) elif evt.type == mesh.MESSAGE_UNI: # Received a message! Display it (and/or decode it): print "Got a message from %s: %s" % (evt.handle, evt.content) # Figure out the nick of whoever sent it: print "It was from buddy %s" % (mesh.get_buddy(evt.handle).props.nick)
Troubleshooting
Ensure you are using build >=432. Also ensure you are using a checkout of the wrapper (recent as of Jul 12) from the Git repository.
Check your log files. Alt+0 on the XO will bring up the developer console. Look at the Log Viewer and select your activity's logfile, and look at the output/traceback.
lincolnquirk is the current maintainer of the wrapper, and resides in the #olpc-content IRC channel (Freenode, like other OLPC channels). Contact him if you get stuck, and bring your logfiles.