An Architecture for large projects

How large is your BGE project? How many blend files? How many different python modules/packages? How many do you expect it to be when the project is done? If the answer is one blend file, this post isn’t so useful. If the answer is several dozen blend files and several thousand lines of code, then this may be interesting to you

The base of all of this is:***How do you write components that are easily reusable?
***Let’s say I have a file selector in BGE:


What makes up this filebrowser?

  • An arrangement of blender objects
  • A specific python ‘filebrowser’ module
  • A dependency on a GUI toolbox to simplify the UI code

If I want to make this filebrowser a useful component, It needs to have a well defined external interface. In Python, creating it needs to be as simple as:


file_browser = FileBrowser(start_path, file_type_list, spawn_location, heading)

And getting the selected path needs to be as simple as:


if not file_browser.alive:
    print(file_browser.selected)

# Or you can bind to a callback
filebrowser.on_done(some_function)

This would be great if a component was 100% python, but it’s not. Somehow, it needs to get a whole bunch of objects into the scene! In a tiny project, you do this by having the objects in the scene initially. In a slightly bigger project you have them linked in statically, in a massive project you have them LibLoaded in when needed. I’m going to ignore the first option, as both the second versions can be solved at the same time.
- Have all the objects added in the class constructor
- Have all the objects grouped

  • Have all the objects on a hidden layer when you save the blend

How does this solve the problem? Well, to add them to your project you can either statically link the objects into a hidden layer, and then creating an instance of the class will add all the objects. Or you can LibLoad them in as needed. Bonus points if you do this inside the class’s constructor.

And so we have an easy to use system. From our new project, we can link in a hidden group, and from our code we can create an instance of it and have it appear. This module is easy enough to be reusable in a variety of projects. Unfortunately this filebrowser was developed for my employer, so I cannot distribute it here.

***How do you structure a component to make it easy to include in a project***Let’s take our file browser again, let’s say it needs to be used in a whole heap of different projects. We need to be able to include it somehow into every project - ideally in some way such that it can be updated across all of them as needed. Enter git submodules. These allow you to take one repository and put it in another. The only issue is that the folder get’s the name of the repository, and somehow we need to be able to access all the python scripts inside the repository.
Thankfully, that’s quite simple to solve, as we can treat the whole thing as a python package
- Write your code in a file called init.py in the root of the repository (or import it into said file)

  • Import your code from outside using import <repository_name>
  • Have a subfolder in the repository to contain the blend files

Now we can put somewhere in the python path and import the code. Linking blends is always a pain, and we may as well keep ones associated with the component in the component folder. For the filebrowser, because you may want to skin it, there is an example file browser in the component repository which you can use, but it is intended you make your own themed one for each project.
So the filebrowser git repository looks something like:


__init__.py 
filebrowser.py
filelist.py
Blends:
 - UnthemedFileBrowser.blend

***How do you structure a project that uses components***It isn’t uncommon to see a project something like:

  • main_blend.blend
  • Data
    — Textures
    — Models
    — Audio
    — Levels
    — Scripts

And then to sort things pretty much by filetype. However, we now have components with a mix of filetypes, so we cannot have items sorted by type. At the moment I just renamed the ‘Scripts’ directory into ‘Components’, and have it otherwise much the same. If anyone has any ideas, I’d like to hear them.
***Why The Component Architecture, why not a framework?***Three reasons:

  • It promotes well-designed interfaces, allowing code separation.
  • Each component is small and easy to maintain
  • When writing a project, you can easily say “I need X and Y and Z” and grab just what you need - rather than the whole thing.

I enjoy these sort of posts. Sadly with BGE there really is no standard for project layout, so it’s nice to see things like this and do some introspection.

If anyone has any ideas, I’d like to hear them.

Something about stressing to “keep all modules in one place” or “use a naming convention” so you don’t have to worry about importing the wrong module due to name collisions. Especially problematic because folders with linked blends get added to the python path. (And apparently appends too, gotta save and re-open the file)

Anyhow the contents of this post have inspired me to make a few changes. Ever-forward…

I have looked into more exotic methods, but an object representing a system, or a scene representing a system, allows “import” or libload into any project with logic bricks and python intact,

When loading the object in you can set project specific settings (other system gameplay elements)
Added = objectAddedToScene
Added[‘whatever’] =literallyAnything

And some objects simply manage a list if it’s populated, and turn off if it’s empty
(like a ui manager on a seperate scene)

This makes things simple and easy to understand for me,

Objects, scenes, systems and proxy.

Selection methods to trigger functions from a dictionary seems to make everything seem ordered enough for me

ListOfGoals
Clicked icon
Keypress combo etc…