[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] separating pygame dependent code from general code



On Tue, Jun 7, 2011 at 9:52 PM, DR0ID <dr0id@xxxxxxxxxx> wrote:
Hi

In a library, how would pygame dependent code be separated from general code?

Let's say that I write a package named 'mygamepack'. In that package there are some modules that are only dependent on python (general parts) and there are some others using pygame (lib dependent parts). How would that package be split up, so that the general parts could be used by other libraries without adding the pygame dependent parts? I wonder if there is a general way of doing this.

Here are some ideas (as a file layout) how to split it up:

Option 1:

mygamepack
       +-module1.py                # general part
       +-module2.py                # general part
       +-module1pygame.py    # lib part, dependent on pygame
       +-module2pygame.py    # lib part, dependent on pygame
       +-module1otherlib.py    # lib part, dependent on otherlib
       +-module2otherlib.py    # lib part, dependent on otherlib

Pros:
       -all code in one package, imports are no problem

Cons:
       -each supported lib adds bulk and overhead
       -separation is not that clean



or split it on package level:

Option 2:

mygamepack
       +-module1.py                # general part
       +-module2.py                # general part
mygamepackpygame        # imports mygamepack!
       +-module1.py    # lib part, dependent on pygame
       +-module2.py    # lib part, dependent on pygame
mygamepackotherlib        # imports mygamepack!
       +-module1.py    # lib part, dependent on otherlib
       +-module2.py    # lib part, dependent on otherlib


usage if using it in a skellington:

mygame
       +-data
       +-gamelib
               +-mygamepackpygame        # local copy, importing mygamepack using relative imports
                           +-mygamepack            # local copy


Pros:
       -clearly separates the general from lib dependent code

Cons:
       -if packages are not on pythonpath or site-packages, need to import general lib relatively


Maybe there are other pros and cons I didn't think of!

Thanks for your opinions and suggestions.

~DR0ID
Hi,

    Going to use real-life examples from my development of glLibPy and glLibC.  I provide many examples, which can be safely skimmed without losing my point.

    I think there's absolutely nothing wrong with choosing a few good, stable libraries as "dependencies" for all of your code.  PyGame, PyOpenGL, and NumPy are classics--usable, well-made, and powerful.  This allows me to do things that a simple, per-file dependency-based model doesn't let you do. 

    Generally libraries are modular, in that components either stand alone, or are closely related to each other. 
    For instance, the graphics code in glLibPy (texturing, shading, object loading, etc.) is all very closely related, and all depend on PyGame and PyOpenGL.  This allows instances of my texture class to be passed to texture units in my shader class, in a different file.  The objects load images directly into the texture classes, so rendering from them is seamless.  The texture class meshes perfectly with the framebuffer object class, the fluid, light, and material classes, and so on.  Convenience functions follow naturally, and make programming easier and more enjoyable. 
    However, in the same library, the math code (matrices, quaternions, vectors, utility functions, etc.) is all grouped together, depending only on the math library included with Python.  The matrix class can be multiplied against vector elements, even though they aren't in the same class.  Trigonometic rotation matrices and quaternions convert easily and integrate nicely with numerical solvers, like conjugate gradient. 

    In a sense, the graphics code and the mathematics code are unrelated.  But I think looking at it that way defeats the purpose of a library--code should be organized by function, not by dependency; in the aforementioned example, that the graphics source files share dependencies is a happy coincidence--I didn't design the library that way. 
    And it's fortunate that I didn't.  I soon realized that the mathematical formulations and the graphics code should be completely intertwined.  It makes sense to let matrices get loaded into OpenGL with glLoadMatrixf(...).  It makes sense that you might want to calculate the volume of a polygonal object.  Et cetera, and so the two were merged.  If I had tried to keep the dependecies separate, it would have devolved into a mess. 

    As a typical consideration, does CPU extrusion of line segments into quads fall under "graphics" or "mathematics"?  On the one hand, I'll definitely need access to glBegin(...), glEnd(), glVertex*f(...), glTexCoord*f(...), but on the other hand, it would be nice to have access to my cross product, dot product, vector operation, and matrix class.  So now I need Python's math library, and PyOpenGL.  If I want it be fast, I also need NumPy--or maybe even a C binding layer to be built into the library later.  But then suppose I wanted to generalize to extrude lines for SDL raster graphics?  Now I need PyGame too.  But now I want to subclass the framebuffer class to make your lines drawable to a saveable entity, so now I'm bringing in PIL and all my texturing code and its dependencies.  Now I want to write this code into a shader, so I'm bringing in the SVG libraries, reverse engineering them, and adding in OpenGL extensions and a GLSL compiler. 
    Okay, so I'm done with that--let's move on to another file for post processing filters.  Do I want runtime Gaussian filters?  Bring in SciPy.  Add to glConvolutionFilter2D(...)?--bring in OpenGL, bring in OpenGL extensions, bring in PyGame, and before long, you realize you're going down the exact same path. 
    I have continued this model of importing everything with other modules--Physics, Math, AI, Graphics/Rendering, Algorithms, Light Transport, Ray Tracing, and so on.  Each time I add a new file, I think about how it will be used later, and how things should obviously connect.  I then make those connections.  In my opinion, this makes robust, intuitive, readable, and easily constructed code. 

    Bottom line: in my libraries, I have a single file with all the dependencies in it that I import with all my files.  If I someday happen to need a math.atan2(...) in my shader class, I won't have to add "from math import *" to that specific file and then worry about the imports being consistent among the rest of the files.  I just import everything in one file be done with it--it's easier, possibly faster, less-bug-prone, neater, and less time-consuming. 

Thanks,
Ian