1
$\begingroup$

I have a game (toy) that works in PyGamek, and I'm trying to port it to Blender. I'm very familiar with both Blender and Python individually, but not together.

In this case, I have a class called "Critter." Each critter knows how to do things like drawSelf() and chooseNewOrientation() and predate(other_critter) and getPredated(other_critter) other fun things like that.

What is the "Blenderic" method for me to implement this class in BGE?

It seems like each OBJECT (mesh) is the parallel to an instance of the class, and that has worked well enough. But I suspect that if I just define the class in a script and attach it to an object (even a single object that never gets duplicated), the class will get defined every frame... which I'd like to avoid, obviously. Right now, I have individual functions in a script on each critter, and that works well enough so long as those are static functions (or would qualify to be static). I'm not sure how to handle things like class member functions/variables. I.e. it'd be nice for each critter to have a "self.diameter" that can tell the "self.drawSelf()" function how big this instance is supposed to be.

So, what's the best way (conceptually) to handle the equivalent of a class in BGE that can spawn instances of itself, which know about members?

$\endgroup$
1
$\begingroup$

There are a couple of ways. Here is a simple one:

Write your class e.g. Character.

Character object knows the game objects of the character.

class Character():
    def __init__(self):
        self.skeleton = None
        self.leftHand = None
        self.rightHand = None
        ...

# builder
character = Character()
character.skeleton = scene.objects["Armature"]
character.leftHand = scene.objects["Hand.L"]
...

The game objects might need to know the Character object too:

character.skeleton["character"] = character
character.leftHand["character"] = character

This way you get a cross reference. When you know one of the game objects you can get the according character:

character = gameObject["character"]

When you know the character instance you do not need to dig through the properties anymore.

You could create a factory that establishes these cross references. This keeps this "management" code away from the character's behavior.

You can dynamically exchange references. E.g. the character grabs a book. So you can assign the book to the right hand. You character eats the apple it holds in right hand, you can remove the link between the apple and the right hand, then you can end the apple.

Be aware the BGE events are always applied to game objects (such as collision, ray ...). As said you can get the python character via property.

myCharacter = owner["character"]
hitObject = sensor.hitObject
hitCharacter = hitObject["character"]
$\endgroup$
  • $\begingroup$ This is very helpful! One additional question, do I have to worry about BGE calling my declaration 60 times per second? Does BGE know to ignore that part of the script, or is there somewhere specific I can put it, so that it only gets declared on launch, and not on every frame? $\endgroup$ – Matt Apr 11 '18 at 13:34
  • $\begingroup$ The BGE logic brick system is an event system. This means you setup sensors to measure the event you are interested in. They trigger controllers that should care the operations on the according events. Your single python controller can evaluate the sensor output even further to start one or more operations. Each controller will be executed maximum once per frame. So it is a question of how you setup the sensors how often a controller gets triggered. $\endgroup$ – Monster Apr 12 '18 at 4:09
  • 1
    $\begingroup$ According to your question: When you know operations that are just called once, you can easily separate it and perform than before operations that rely on the result of them. E.g. you can trigger a factory operation when an object just was created (always sensor). This operation creates your Python object and creates the above cross references. The "daily business" runs later and assumes everything is already setup. It should be triggered by other sensors and be placed in separate controllers. These are different operations anyway. So it makes your code cleaner. $\endgroup$ – Monster Apr 12 '18 at 4:13
  • $\begingroup$ "Duh" I totally forgot that the only reason that the Python runs every frame is because of the "always" sensor. If I just set that sensor differently for the object that has my class declarations, factories, etc in it, then it'll get called only once, or only when I need it. Thanks! $\endgroup$ – Matt Apr 13 '18 at 12:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.