BGE scripting in an object oriented way

Hey all,

First of all great that blender artists is back up! With a friends group we are currently working on blender to set up a game like micro machines. The concept is relatively easy and I think its a nice start to try the potential of blender. The modelling doesn’t seem to be a big problem, but the blender BGE is more complex. Especially in 2.5, although it should also be possible here since we are using basic logic.

The situation at the moment is that I have:

  • A car object controlled by a movement script (in fact I have 4 cars like that).
  • A camera controlled by a cameraControl script, placing the camera based on the location of the cars and reporting when the cars are out of sight.

This is working, but I have to set some variables (e.g. car object name) in the script, which I would rather prefer to set from 1 central control point (the GameModule). Currently I’m playing around with a cube (the GameModule), which has a controller (the GameModuleScript). In this script I want to define all the variables needed for the various scripts.

So the situation is:

  • I have a script running on the camera
  • I want to have a script running on the GameModule

From the CameraScript I want to call methods from the GameModuleScript. Being in the CameraScript I can get the GameModule object, it’s controller and finnaly the script, but I can’t call any methods from that script. E.g. GetActiveCars() --> returning the 4 car objects of the level.

From examples I note that most people throw all logic inside one script, but I want only the logic relevant for the object to be inside a script, more object oriented. What is the best way to deal with this problem? Is it actually possible to have something like a MainScript, calling functions from other scripts?

Any advice is welcome and would be greatly appreciated,

Regards, Wouter

Hi Wouter,

there are multiple solutions for this situation. I think it is good that you already choose the way to modularize and parametrize your code.

The usual way to set paramters is via properties.
As this is not always applicable (e.g for GameObject references) you can also use parents, children, sensor owner, actuator owner, sensor hitobjects etc.

First, you might want to switch from scripting mode to module mode. This allows you have multiple BGE access points in one file. This is quite handy for organising the code. But this is not absolutly necessary.

By writing modules, you can import this module in other scripts and call functions of it. These functions should be aware that they can be called from different controllers on different objects.
e.g.


#--- BGE callable functions
def myFunction(cont):
  own = cont.owner
  called = own.get("called",1)
  print ("I was called by %s from %s the %i time" % (cont.name, own.name, called))
  own["called"] = called + 1

There are several methods to achieve this without the need to change the python file. You can place one of them in your getActiveCars() ;):

search through the object list for a specifc name:


nameToSearchFor = "Car"
allObjects = GameLogic.getCurrentScene().objects
cars = [obj for obj in allObjects if obj.name == nameToSearchFor]

search through the object list for a specifc property:


propertyToSearchFor = "Car"
allObjects = GameLogic.getCurrentScene().objects
cars = [obj for obj in allObjects if propertyToSearchFor in obj ]

Hey Monster,

Thanks a lot for your reponse, you put quite some efforts in it which is much appreciated :slight_smile:

I wasn’t aware of the BGE callable function nor the BGE access points, this is valuable information for sure. It might even be a potential solution, depending on how it exactly works :slight_smile: I will certainly check it out, thanks for pointing me at it!

The problem with searching through the object list with a specific name, is that you have to be aware of the objects name. I want to avoid that I have to adjust 6 scripts, just because I change a car name / want to use a different car type. I want to manage this at a certain fixed place, hence the idea of a game module (1 place to change and set the names of the car objects to be used).

The idea with properties is also something that I considered (didn’t know the syntax yet for searching though, so thanks for pointing me at that as well :slight_smile: ). This solution will work when you use 1 car type, but with multiple car types I foresee problems… The way (I think) that blender works is that you need to have all the car objects in your game. So lets say this game is playable for 4 people, then I have to add 4 cars of 1 type. If I add another type then I have 4x2 cars, etc. When I attach a property to this object, indicating that it is a car then such a searching function will give me 8 cars back (when I use 2 car types).

Of course I can then add another property, indicating that it has to be a) a car, and b) an active car. My first thought is that it is less maintainable and the search function will become rather expensive. Having defined all variables at one place should be cheaper performance wise and more maintainable. I will have to give this a second thought though… maybe this just has got to be the way to go… I dont know yet…

How about the original idea I had earlier? I tried to do the following:

scene = GameLogic.getCurrentScene()
objList = scene.objects
gameModule = objList[“GameModule”] #this is just a cube, with 1 sensor containing a phyton script
gameModuleControllers = gameModule.controllers
scriptController = gameModuleControllers[0]
script = scriptController.script
result = script.main() # trying to invoke the main() method of the script, which fails

The Blender API says that the function returns my entire script in a string. Assuming that my variables are defined within this script (maybe even set through properties), I would like to invoke a method of that script. How can I do that? This probably won’t be great performance wise either, but at least I can define names in that script and return them from a central place.

Another Idea which I have in my mind is related to scriptlinks and global variables. I have read something about it, but didn’t have the time yet to check it out. Maybe I should store an active carlist as a global variable or something like, or use the scriptlink to obtain the script where all the items are configured (if such a thing is actually possible). Again I have no clue how this exactly works (yet).

My main goal related to this post is how to set things up so they are maintainable and that all configuration is at a certain place (but still dynamic). Secondairy I was trying to figure how I can invoke methods from other scripts to achieve this… maybe this just has got to be done through the use of properties and sensors… I dont know yet…

Still got some research to be done here, also at the points indicated by Monster. If anyone else has got some good ideas how to set this up, advice is welcome! Thanks in advance,

Regards, Wouter

Actually, Blender will only look through active objects in the current scene (unless you indicate otherwise). If you simply put a ‘car’ property in each of the cars, assuming you only have four cars in the game, looping through the objects in the game for objects with the ‘car’ property will only return the four cars.

As for invoking functions, I think the script file you wish to access has to be a script module (set that in the python controller for the script). Also, I think you’ll need to access the module by the module name (i.e. modulename.main()).

Cheers m8! Will check it out. Blender is just awesome :smiley:

With your explaination it is a bit more clear what you want to achieve.

I suggest following:

Make your cars including scripts complete independent from eachother. That means the script/module knows what objects to work with (car, wheels whatever) just by looking for the owner of the python controller. In that case it does not matter what name the object has because it’s reference is already known.

The interface to other objects/controls should be by properties. That means you can transfer data just by setting a property at a specific car.
If you are watching the properties (via property sensor) you can update your car with the new data. For example your GameModule object can set the properties on any car.

BTW. If the GameModule does logic only, it should be an empty rather than a cube. As an empty it does not cost any render time.

Another hint:
a car could register itself at the GameModule, just by adding itself to a list which is placed in a property of the GameObject:

gameModule.py:


def register(cont):
  ''' registers the owner of this controller at the GameModule in property "cars" '''
  car = cont.owner
  scene = GameLogic.getCurrentScene()
  allObjects = scene.objects
  gameModule = allObjects["GameModule"]
  cars = gameModule.get("cars")
  if cars == None:
    cars = []
    gameModule["cars"] = cars
  cars.append(car)

Register a car with:
always sensor (no pulses) -> Python Module: “gameModul.register”
at the car!

Any object (incl. the GameModule) can access this list just with:


...
cars = gameModule.get("cars") 
if cars is None:
  return# just make sure the list is not None ;)

# direct access
car1 = cars[0]
# looping through all cars
for car in cars:
  print (car.name)

Awesome, this is exactly what I was looking for! This will do the trick for being both modular and maintainable :slight_smile: thanks!