Package: pysdl2-harness
These are a set of classes to make easier to usepysdl2.This is a work in progress so use it at your own risk!RequiredPython 3 (Python 2.7.x may work, but is not a priority!)pysdl2SDL2 and SDL2_Mixer installed in your systemOptionally SDL2_Image (otherwise only uncompressed BMP images are supported)InstallationThe easiest way to install Harness is usingpip:$pipinstallpysdl2-harnessHow does it looks like?It is inspired bypygletand specially focused
on 2D games.Example:#!/usr/bin/env pythonfromharnessimportHarnessgame=Harness(width=320,height=240,zoom=3)title=game.load_resource("title.bmp")@game.drawdefdraw(renderer):renderer.draw(title,10,10)@game.updatedefupdate(dt):ifgame.keys[game.KEY_ESCAPE]:game.quit()game.loop()Seeharnessmodule docstrings for a complete list of classes and methods.There’s an example game inexample.pyand remember that you can still usepysdl2directly if you need to!ComponentsHarness tries to provide a clean and simple interface to the following
components:The game loopResource managementControlsAudio1. The game loopHarness implements a game loop with a fixed frame rate determined by the vsync
of the screen (usually 60 FPS), with support for fixed updates for the game
logic (by default at 80 times per second).The usual workflow is:Create a Harness object (we’ll call itgamein the examples).Load resources.Declare the draw and update functions.Run theloop()method in your Harness instance.The game loop should be called once and it will run until the game is quitted
(eg, usingquit()method).Draw functions can be defined with thedrawdecorator, and update
functions with theupdatedecorator.The draw functions should expect a “renderer” parameter that allows to draw
textures, bitmap fonts, etc.Example:game=Harness()tex=game.load_resource("bitmap.bmp")@game.drawdefdraw(renderer):renderer.draw(tex)game.loop()The update function should expect a “dt” parameter that provides the delta
time (time elapsed between updates); in this case fixed atHarness.UFPS_DT(1 / UFPS).Example:game=Harness()@game.updatedefupdate(dt):print("%selapsed since last update"%dt)game.loop()Several draw and update functions can be defined and they will be run in the
same order they were defined.The game instance can be accessed from the update function to test for key
states, quit the game, etc.The methodquit()can be used to exit the game loop.Example:game=Harness()@game.updatedefupdate(dt):ifgame.keys[game.KEY_ESCAPE]:game.quit()# in case we don't want to complete the updatereturngame.loop()A draw or update function can be removed from the game loop withremove_handler()method, passing the function to be removed as parameter.Example:game=Harness()debug=Falsedefupdate_debug(dt):print(dt)@game.updatedefupdate(dt):globaldebugifgame.keys[game.KEY_D]:print("D was pressed!")ifdebug:# remove the update_debug update functiongame.remove_handler(update_debug)else:# add a new update functiongame.update(update_debug)debug=notdebug# remove the key press once processedgame.keys[game.KEY_D]=Falseifgame.keys[game.KEY_ESCAPE]:game.quit()game.loop()2. Loading resourcesResources can loaded withload_resource()method. This method allows loading
resources searching for them in the paths specified in theresource_pathlist.By default the files will be searched for in the “data” subdirectory at the same
level as the script running the game.Depending on the resource some extra libraries may be required in the system
(eg,SDL_Image).Resources not in use can be freed usingfree_resources()method, but
be careful to not use any reference to the resource once it has been released.Harness will free all resources after exiting the game loop.2.1 Bitmap fontsThe methodload_bitmap_font()can be used to load a image that will be used to draw
text withrenderer.draw_text(). Harness will map a text string into a fixed
width and height part of the font image.Example:game=Harness()font=game.load_bitmap_font("font.png",width=6,height=10)@game.drawdefdraw(renderer):renderer.draw_text(font,10,10,"This is a text!")game.loop()Fonts can be freed withfree_resources().3. ControlsThe state of the keys is exposed inkeysdictionary and it
gets updated in each game loop iteration.InHarness.KEY_*there are constants to test in thekeysdictionary. If a key
is being pressed, the value in the dictionary will beTrue.Example:game=Harness()@game.updatedefupdate(dt):ifgame.keys[game.KEY_ESCAPE]:game.quit()game.loop()3.1 Game controllersGame controllers can be mapped into key states so the game can access to the
controller like the player was using the keyboard.The default mapping is:DPad up: up arrow keyDPad down: down arrow keyDPad left: left arrow keyDPad right: right arrow keyButton A: key cButton B: key vStart button: key sBack button: escape keyHarness will manage the controller automatically in the game loop updating thekeysdictionary as needed.has_controllersproperty can be checked to see if any game controller was
detected. Harness includes a game controller database with definitions for most
common devices, and SDL2 functions can be used to add more. If there’s no information
about a given controller, it will be silently ignored.In order to use a controller, thecontrollersproperty can be accessed to
activate any detected controller.Example:game=Harness()# enumerate all detected controllersforcontrolleringame.controllers:print(controller.name)Once the controller has been activated, it can be deactivated usingclose()controller method.The key mapping can be changed using theset_mapping()method on the controller.Example:game=Harness()# first controllercontroller=game.controllers[0]# remap button a to key acontroller.set_mapping(a="KEY_A")The valid parameters are: up, down, left, right, a, b, start and back. Use a
string defining the key (seeHarness.KEY_*).The use of a controller won’t disable the keyboard. If that is required, the
game controllers can be accessed using SDL2 functions directly.4. AudioThe methodplay()can be used to play a sample loaded withload_resource().
Optionally aloopsparameter can be provided stating how many times the sample
will be repeated (use -1 for an infinite loop).By default .ogg and .wav files are supported (in theory it could load any
format supported bySDL_Mixerbut Harness will only identify files with the
aforementioned extensions).play()returns the channel number used to play the sample and that
number can be used to muted the channel withstop_playback()(if a channel
number s not provided, it will stop all channels).By defaultHarness.AUDIO_CHANNELSchannels are allocated (6 channels).Using OOPHarness can be used in a class to take advantage of object oriented programming
and avoid the use of global variables. Just use composition and register the
update and draw methods withupdate()anddraw()instead of using the
decorators:Example:fromharnessimportHarnessclassMyGame(object):def__init__(self):self.harness=Harness()# register update and draw methodsself.harness.update(self.update)self.harness.draw(self.draw)# load some resourcesself.image=self.harness.load_resource("image.png")defrun(self):self.harness.loop()defupdate(self,dt):ifself.harness.keys[self.harness.KEY_ESCAPE]:self.harness.quit()defdraw(self,renderer):renderer.draw(self.image)if__name__=="__main__":game=MyGame()game.run()Seeexample-oop.py.Author and ContributorsJuan J. Martinez <jjm@usebox.net>This is free software under MIT license terms.Contributors:Your name here?