Design patterns and conventions

Hi,
I’m planning a replacement of ShowBase.py with all its features. I think it’s obvious that ShowBase does way too much for one class, not to mention its builtin violations. I have a few classes in mind already, like “window.py”, “scenegraph.py”, “controlstate.py” and so on.
I won’t elaborate on it yet. First I’d like to hear what ideas you have or even what patterns are in use already.

I saw people writing classes that do everything about a certain object in game, like “Sky”, “Environment”, “Player”, “Car” and so on, where nearly everything is done implicitly. You instanciate the class and already have a new node attached to the scenegraph. This is one of the design patterns I’d like to investigate.

How do you organize your game? What classes do you have and how do they interact? How would you wish Panda to behave? Do you know of any other engines behaving all different?

Thanks for answers in advance.

With my first test project in panda I made classes like I would do in AS3 :

  • Game
  • Camera
  • Environment
  • Player
  • Keyboard
  • Renderer / Lighting
  • Menu
  • Particles
  • Score
  • Ennemy

(was for a shmup)

One thing I couldn’t do in Python is make one class inherits from an other class, like in AS3 you make the Ennemy class inherits from MovieClip or Sprite.

I wanted to make for example the class Ennemy inherits from PandaNode or smth but couldn’t success :confused:

Hey, not really a design pattern, but i kind of abuse setPythonTag(). With that, you have to be careful about cleanup, but other than that, it is very useful.

Alos, it works well for simple game.

there is one “World” object, it is root of everything
world.btWorld is instance of BulletWorld

“World” is property of “Game”, and “Game” inherited ShowBase.

“pseudo” code for Weapon class:
#think weapon like in Freelancer.

class Weapon():
  def __init__(self, parent):
    #parent is ship (spacehip)
    self.parent = parent
    self.world = parent.world
    self.NP = loadModel()
    
    #not exactly like this, but...
    self.btNode= createBulletNode()
    self.btNode.setPythonTag("pyObject",self)

edit1:

game:
  world:
    player:
      input for player
      ship:
        weapons:
          bullets
    enemies:
      ship:
        weapons...

How do I organize my game?

At a high level, I organize my game’s Python packages according to CCP (Common Closure Principle) - I put classes that will change together in the same package (or module, if they are very related). I then apply REP (Reuse/Release Equivalence Principle) to make sure that all the classes in the package will be re-used together (i.e, they are related in some manner).

For example, in my primary Panda project, OpenBlox (I have multiple Panda projects), my custom VFS and asynchronous frameworks each get their own packages, and utilities related to each framework go in that framework’s respective package. If the utility is not used by my project’s core engine (i.e, it is meant to be used by users), it goes in a plugin.

In general, my engine is organized into the following subsystems:

  • VFS subsystem
  • Asynchronous subsystem
  • Plugin subsystem
  • Lua scripting subsystem
  • Configuration subsystem

Each subsystem works independently of the others. To get game-specific features (in OpenBlox’s case, Lego bricks), plugins are used. Plugins are a great way to abstract away various parts of your game (even my engine’s interface to Panda is a collection of plugins); because OpenBlox’s core is so resuable, I’m able to use most of its code for other projects I have.

What classes do you have and how do they interact?

I have 1 class for each single feature I need. For example, in OpenBlox (again, my primary Panda project), there are Lua scripts that can be run, and be put on the scene graph. That’s two separate features, and thus they each have separate classes to handle them: LuaEngine for the script runner, and LuaElement for the scene graph element. In general, OpenBlox classes interact on a per-instance basis; there are no globals, save for the plugin manager, which I’m refactoring. This not only makes them easier to test in isolation, it makes them easy to pull out and reuse with other projects.

How would you wish Panda to behave?

  • I wish Panda were more plugin-oriented; this would make it both easier to extend and modify
  • I wish Panda did away with all (or at least most) of its globals; it’s very hard to run unit tests on the parts of my code that uses Panda
  • I wish ShowBase was broken up into several (non-global) classes, like RenderWindow (which would give a drawing surface to render on), ModelLoader, and so on. This would also make code easier to test
  • I wish Panda’s Python interface conformed to PEP8; most of the Python libraries out there also follow PEP8, but this isn’t as important as the other things on my wishlist

Do you know of any engines behaving differently?

Crystal Space has a very plugin-oriented architecture, even more so than OpenBlox. Even the Crystal Space VFS is a plugin. Irrlicht uses a Singleton-based system, somewhat like Panda’s, but they hide their globals behind accessor functions. I don’t know what OGRE does.

I do something similar to what Manou and DONTR does.

@Manou: I am pretty sure python has inheritance.

Correct - Python does have inheritance.

This may be a shock to some, but I don’t organize my code (until I realy need to).
I’ve got a World class and a game task and I put stuff inside those as I go along.

That’s just asking for trouble, you know. :stuck_out_tongue:

I know, but if my whole game has 1-2k lines (with comments), then it would take more time for me to organize the code then just to write it.

Only for the first time you write your game. As you add features you didn’t think of before, and fix bugs, the time taken will skyrocket pass the amount of time you would have taken if you had organized your game in the first place. Well-organized code is far easier to modify and maintain than “hacky” code.

There is something to be said for code that works, but if it is not the best, most beautiful code you can write, it needs to change - there is no excuse IMHO for anything but your best.

When I write code, I try to imagine me taking a look at it 5-10 years from now. I want that future me to be impressed at the work I’ve done, to be proud that I had a hand in it. I do this because code I wrote 5 years ago is not something I’m proud of now, and 5 years down the line, I’d rather that not happen again. I know 5-10 years down the line, I’ll have learned of coding practices and design patterns I don’t know of now, but future me knows that; he knows what I’m capable of now, and expects I do the best I can with what I know. If you don’t do something with excellence, it’s not worth doing IMHO.

I know all about deadlines and things like that - however, that’s when coding practices need to be stuck to most, since they help in the long and short run.

Thank you all for the responses.

I inspected ShowBase.py a bit and came out with this diagram showing its current responsibilities.


The colors of the labels mean:
orange – needs to be (re)written
blue – needs a new access point or should be rewritten a bit

I will extend that list and try to categorize the functions from ShowBase.py, as well as rewrite some of the given Python classes.

First one will be Loader, I guess. It has a circular dependency (when it comes to loading audio files) and could be easily made fully independent.[/img]

I don’t understand how the ShaderGenerator has anything to do with ShowBase, though. It’s implemented in C++ entirely.