Archive for the Programming Category

Initial release of PyGLy

Posted in Development, Programming, Twisted Pair with tags , , , , on 2012/03/07 by Adam Griffiths

It’s a pretty big day for us, as I’m pushing my labor of love, PyGLy, to GitHub.

PyGLy is a 3D framework developed in pure python.

I’ve been dismayed at the state of game frameworks on Python.

There are a large number of quality 3D engines and frameworks out there. However, there are serious problems with the ‘engines’ out there that have Python bindings.

  • Not truly cross-platform (this is Python FFS!).
  • Not free.
  • Not maintained.
  • No documentation (the worst culprit).
  • Bindings are 2nd class citizens and you still need to code C/C++/Whatever.
  • Don’t work with latest versions of code.

Most engines have bindings created by the community. The problem is these are quickly dumped when the person moves on.

Python only 3D engines seem… well… stagnant.

  • PySoya and PySoy seem to be seething at each other but not really producing much.
  • PyGame is just SDL in disguise.
  • The rest… well they all 404 now.

For the most part, 3D game development on Python is dead.

So, behind the scenes, I’ve been writing my own 3D framework for Python, PyGLy.

“Framework” is an important word there. PyGLy does not force any one methodology on you. PyGLy simply provides functionality to wrap common functionality. Windows, Viewports, Scene Graph Nodes, Cameras. It’s up to you to put them together how you want.

Obviously some things are going to be coupled together. But for the most part, PyGLy just gets out of the way.

At the moment PyGLy is quite small, but it is in active development and already has features that may interest some.

I think the best case for it at the moment is for people wanting to rapidly prototype in 3D but not be abstracted from the rendering process. PyGLy lets you forget about the scene graph and just concentrate on rendering your objects. Rendering is performed via callbacks. You can make any OpenGL call you want in these callbacks.

PyGLy is the foundation of our Python 3D work, so expect it to be actively developed going forward.

The following are some of the things that we’re wanting to add in the future:

  • Shadowing.
  • Scene management (Octree, etc).
  • Cocos2D integration (CCLayer).
  • Separate OpenGL 3+ path.

As we’ve said before, Twisted Pair are true believers of Open Source, so you can find PyGLy on our GitHub repository under a very liberal license.

Animation support for CCTMXTiledMap

Posted in Development, Programming with tags , , , , , on 2012/03/07 by Adam Griffiths

I spent today learning Objective-C and working on a small module for one of our up and coming projects.

The outcome of this was CCAnimatedTMXTiledMap. A class that adds animation support to CCTMXTiledMap in Cocos2D-iphone / Kobold2D.

Twisted Pair are true believers in support Open Source and as such we’ve published the source code to our Github repository.

Python weak references to Methods and Functions

Posted in Development, How To, Programming with tags , , on 2012/03/01 by Adam Griffiths

The ‘weakref’ module in Python cannot store pointers to methods (there are exceptions but basically you can’t).

The following is a module I’ve written to bypass this. It is essentially code from the following sites, but improved by myself for storing them in containers like set([]).

References:
[1] [2]

Continue reading

Installing Pyglet in Mac OS X

Posted in Development, Platforms, Programming with tags , , , , , on 2012/02/21 by Adam Griffiths

Pyglet is a common requirement for many Python applications, a major one being Cocos2D.

But it doesn’t work out of the box. Running a Pyglet application will result in the following error:

OSError: dlopen(/System/Library/Frameworks/QuickTime.framework/QuickTime, 6): no suitable image found.  Did find:

/System/Library/Frameworks/QuickTime.framework/QuickTime: mach-o, but wrong architecture

/System/Library/Frameworks/QuickTime.framework/QuickTime: mach-o, but wrong architecture

The following are the steps to take to get Pyglet and PyObjc installed on OS-X (tested with 10.7 Lion).

Pyglet 1.1 uses the Carbon framework, but this is not compatible with 64-bit Python installs. The Pyglet 1.2 branch has been modified to use Quartz, but no releases of this branch have seen the light of day (sigh). We must instead install Pyglet from the Mercurial repository.

The Quartz bindings require the use of PyObjc but the latest versions do not work with Pip. The patches to PyObjc’s setup.py that I’ve seen on the internet do not work for me. The following is the only method I’ve had work.

Remove any existing Pyglet install

pip uninstall pyglet

Install Pyglet from the repository

pip install hg+https://pyglet.googlecode.com/hg/

Edit: The following is no longer needed

We need to install PyObjc for the new Pyglet Quartz API. But PyObjc is horribly broken and the latest version does not install with Pip or easy_install.

We must instead install an older version.

pip install pyobjc==2.2

You should now have a working Pyglet installation.

Installing Python with pythonbrew on Mac OS-X

Posted in How To, Programming with tags , , on 2012/01/16 by Adam Griffiths

Virtualenv, virtualenvwrapper and pythonbrew are fantastic tools for developing with Python.

Using Pythonbrew to install Python on OS-X triggers some failures which prevent it being installed.

Continue reading

Pyglet mouse events and rendering

Posted in Development, How To, Programming with tags , , , , on 2011/06/28 by Adam Griffiths

The Problem

I added mouse event handlers to my Pyglet application recently. I found when I moved the mouse over the window, my rendering started to create “ghost” images.

I finally found the solution hidden in the docs.

The pyglet application event loop dispatches window events (such as for mouse and keyboard input) as they occur and dispatches the on_draw event to each window after every iteration through the loop.

So every mouse move (or any other event) triggers Pyglet to call “on_draw”.

But because I’m controlling my own render loop at 60Hz, I didn’t see a need to hook into this event. So I assume Pyglet is attempting to render the scene itself, and it’s failing miserably.

This is really bad design! What if I have lots of events that are seperate? Looks like Pyglet is going to hammer the “on_draw” event.

The Solution?

Well the basic solution is to ensure you’ve hooked into the “on_draw” event and just connect it to your render call. Don’t connect it to your game update logic or you will end up updating everything.

But…

This means your frame rate will vary depending on user input, and may even end up running balls out. Which could turn a simple game into a system hog. My basic application goes from 1% (of 2 cores on a dual core system), to 20% with the mouse moving.

It also means that you need to decouple the rendering from the system update, as each event you have scheduled will trigger an “on_draw” event. If you don’t decouple them, you will render each frame twice!

The Proper Solution?

We need to over-ride the “EventLoop.idle” method as mentioned in the docs.

The code without “on_draw” looks like this:

def idle( self ):
    """An alternate idle loop than Pyglet's default.

    By default, pyglet calls on_draw after EVERY batch of events
    which without hooking into, causes ghosting
    and if we do hook into it, it means we render after every event
    which is REALLY REALLY BAD
    http://www.pyglet.org/doc/programming_guide/the_application_event_loop.html
    """
    pyglet.clock.tick( poll = True )
    # don't call on_draw
    return pyglet.clock.get_sleep_time( sleep_idle = True )

def patch_idle_loop():
    """Replaces the default Pyglet idle look with the :py:func:`idle` function in this module.
    """
    # check that the event loop has been over-ridden
    if pyglet.app.EventLoop.idle != idle:
        # over-ride the default event loop
        pyglet.app.EventLoop.idle = idle

The “on_draw” function also calls pyglet.window.flip() for us, so now we need to do that after our rendering. So add the following (obviously you need to change the window variable depending on what you’ve called it):

# switch out the default idle function for ours
patch_idle_loop()

def render( self ):
    # do render here
    # flip the buffers
    self.window.flip()

And we’re done! No more superfluous “on_draw” events and my simple application no longer spikes the CPU usage when the mouse is moved!

Registering Event Handlers in Pyglet

Posted in Development, How To, Programming with tags , , , , , on 2011/06/25 by Adam Griffiths

The Problem and Pyglet’s own solutions

Pyglet’s documentation suggests a number of methods to receive events.

The recommended method of using @ decorators works for global methods where the event object is known. But if its for a class method or the event object is passed in later, this will not work.

The alternative is to simply over-write the existing handler with something like

window.on_resize = self.on_resize

Unfortunately most of them end up with the following error:

window.set_handler( window.on_key_release, self.on_key_release )
AttributeError: 'Win32Window' object has no attribute 'on_key_release'

This discussion on the developer list explains it. This method only works when the platform’s window class has an existing method to handle the event. And not all events are handled by default, so when you come across this, BOOM!

Even then, when it works this is also a double edged sword. The existing handlers are there for a reason! For example, if you over-write the on_resize method of Window your application will no longer draw (took me a while to figure this out).

So yes, Pyglet’s documentation is really, REALLY, asking for trouble.

The Proper Solution?

Use the “push_handlers” method.

Pyglet automatically detects a method with the event’s name and dispatches the event.
So we can just add methods to our class and we’ll automatically receive the events.

class Test:
  def attachToWindow( self, window ):
    window.push_handlers( self )

  def on_key_press( self, symbol, modifiers ):
    # method name matches the 'on_key_press' event!
    print "Keypress"

Or we can manually specify which events we care about.
If we do this, we must specify the actual function that receives the event.

class Test:
  def attachToWindow( self, window ):
    window.push_handlers( on_key_press = self.on_key_press )

  def on_key_press( self, symbol, modifiers ):
    # method name matches the 'on_key_press' event!
    print "Keypress"
%d bloggers like this: