0
$\begingroup$

Following the documentation at: https://docs.blender.org/api/blender_python_api_2_76_2/bge.types.KX_GameObject.html I can extend a game object with:

class Mine( types.KX_GameObject ):

    def __init__( self, old_owner): #Note: where has my argument gone?

         #stuff

def activate( controller ): # Called from Controller

    Mine( controller.owner ) # Note: Object is stored nowhere

But I'm missing what's doing the magic here. Somehow the controller not gets passed as second argument to __init__ but as first and the game object is internally (?) exchanged (?) with mine.

So how is this working exactly? Is there some blender-foo or is this something Python can do for me which I'm not aware of?

EDIT: To make it more clearly: If I do "normal" inheritance in Python this is how it works:

class Parent:

    def __init__( self ):
        self.a = "FOO"

    def talk():
        return a

class Child( Parent ):

    def __init__( self, b ):
        Parent.__init__( self )
        self.b = b

    def talk( self ):
        return self.a + self.b


child = Child( "BAR" )
print( child.talk() )

someglobal[ 'child' ] = child

so the parameter "BAR" gets passed as second argument b to the constructor of class A. The constructor calls the other one from class A and I end up with an instance which I have to store somewhere globally in order to access it from somewhere else.

Compare this to blender's version: The already instantiated object is passed as an argument to the constructor. But it doesn't end up as second argument to __init__ but gets somehow mangled in while the second argument is something else (in fact it seems to be nothing. trying to access it yields in an error). The finally constructed instance is then somehow stored in the global dictionary for objects and replaces the old one.

These somehows and somethings are which I'm interested in. What's happening here?

EDIT2: Taken from the linked documentation:

def __init__(self, old_owner):

# "old_owner" can just be ignored. At this point, "self" is
# already the object in the scene, and "old_owner" has been
# destroyed.

If I only read the python code in this module (my first example) this is not what is supposed to happen python-wise. So what makes self the object and what destroys the old owner? Is this some c-code magic patched into the python interpreter? Or is this some python magic somewhere in KX_GameObject? Or something else?

$\endgroup$
  • $\begingroup$ This is explained somewhat in the link you provided in the comments in example code : "KX_GameObject can be subclassed to extend functionality. For example" $\endgroup$ – batFINGER Dec 28 '17 at 12:12
  • $\begingroup$ Thank you for sympathising. But I know that. What I like to know is what makes this work. See perhaps my second edit. $\endgroup$ – Scheintod Dec 28 '17 at 13:08
0
$\begingroup$

When inherit an object you will "merge" the attributes, properties, functions:

class Mine( types.KX_GameObject ):

    def __init__( self, old_owner):
        self.life = 100

def activate( controller ): # Called from Controller

    object = Mine( controller.owner )
    print(object.worldPosition) # [0,0,0] KX_GameObject.worldPosition
    print(object.life) # 100

While no inherit:

class Mine():

    def __init__( self):
        self.life = 100

def activate( controller ): # Called from Controller

    object = Mine()
    print(object.worldPosition) # ERROR
    print(object.life) # 100

About, is this something Python can do for me which I'm not aware of? PY classes class-objects

$\endgroup$
  • $\begingroup$ Hi. Thanks for your answer but that's not what I mean. I think I do know how "normal" Python inheritance works. That's why I'm confused how this thing works in blender. I try to edit my question to make it more clear. $\endgroup$ – Scheintod Dec 28 '17 at 7:53
  • $\begingroup$ I will guess that, as the object (KX_GameObject) that will pass to the child class is already in a memory instance and have its attributes and properties already set the child class is not required to instantiate again that and blender internally maybe does as "the known" python inheritance and returns the new instance with all the attributes set from the old KX_GameObject. $\endgroup$ – Strapicarus Dec 28 '17 at 23:16
0
$\begingroup$

So to answer my own question at least as far as I understand it: The magic is in the C++ code. (But I have never embedded python in C++ and only have a rough understanding whats going on here.)

This is from the sources (148ff): Blender uses for it's own game objects a base class called PyObjectPlus. These classes are references via a proxy class called PyObjectPlus_Proxy.

PyObjectPlus defines a method called 'py_base_new' which is called whenever a new object is created which is based on a game object.

This method checks that the first argument is indeed of the 'cont.owner' type and then replaces the object in memory with the extended one.

So it's not "normal" python at all. This comment is from the Sources (194):

/* invalidate the existing base and return a new subclassed one,
 * this is a bit dodgy in that it also attaches its self to the existing object                      
 * which is not really 'correct' python OO but for our use its OK. */
$\endgroup$

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.