How Do I SubClass From DirectObject?

Sorry, I’m a complete beginner. How do I SubClass from DirectObject to create a Class that can instantiate an actor in the scene and have its own values? Any help would be appreciated.

If I’m understanding you correctly, I wouldn’t recommend sub-classing DirectObject for this purpose, but rather ShowBase.

Something like this:

# Importations of things that we'll be using--in this case,
# ShowBase and Actor.
from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor

# The main "game" class, which sub-classes ShowBase.
class MyGame(ShowBase):
    def __init__(self):
        # Initialise according to the super-class, passing in the object being
        # initialised.
        ShowBase.__init__(self)
        
        # The storage of a simple variable
        self.someValue = 5.0

        # It's important to keep references to Actors; for
        # this simple example, we'll just keep them in a list.
        self.actors = []

        # A simple event that we'll use to spawn our actors
        self.accept("space", self.makeActor)

     # The method that's called by our event, above, and
     # which spawns actors.
    def makeActor():
        # Spawn an actor!
        actor = Actor("modelFile", {"animName" : "animFile"})
        actor.reparentTo(render)
        self.actors.append(actor)


If I may suggest, you might find use in my “beginner’s tutorial”–it covers matters like this, amongst others.

To be specific, it covers the principles of using the engine, starting with the fundamentals and going all the way to the building of a distributable. As part of this, it shows one approach to the internal structure of a game–the “core” game-class and classes for game-objects.

If you’re interested, you can find the tutorial here:

1 Like

Sort of. I want to instantiate actors, but I also want to have values associated with those actors individually. Ideally, it would be a separate class in a separate file, so I could import the class into the main file and call class functions.

Hmm, that’s not necessary.

main.py

from direct.showbase.ShowBase import ShowBase
from characters import Human

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        
        human_1 = Human(self, 
                        model = "models/panda",
                        anim = {"walk":"models/panda-walk4"},
                        name = "Price",
                        rank = "Captain",
                        pos = (0, 0, 0))

        human_2 = Human(self, 
                        model = "models/panda",
                        anim = {"walk":"models/panda-walk4"},
                        name = "Soap",
                        rank = "Soldier",
                        pos = (20, 0, 0))

        #print(human_1.name)
        #print(human_2.name)
        
        # Or:
        
        human_1.get_name()
        human_2.get_name()


app = MyApp()
app.run()

characters.py

from direct.actor.Actor import Actor

class Human():
    def __init__(self, base, model, anim, name, rank, pos):
        self.name = name
        self.rank = rank
        self.actor = Actor(model, anim)
        self.actor.setPos(pos)
        self.actor.reparentTo(render)

        base.accept('enter', self.get_name)

    def get_name(self):
        print(self.name)

Note that I passed the base reference to the class for the example, it is not needed. This is indicated by the enter key that works, but it will only work for the last instance.

1 Like

Thanks! This was basically what I was looking for. Do I save this file in the same folder as main?

You can put it anywhere you want. You will only need to change this in the from section.
example:

from myfoder1.myfolder2.characters import Human

I tried doing this, but now after I run main, it crashes and I get a folder called pychache with a compiled python file inside,

Are any errors printed out? If so, what are they?

Personally, I don’t recommend passing “base” around via parameters like this–it can become unwieldy, as more and more classes or functions require it. And if it’s stored in a variable of the classes in question, then it can make for a circular reference, which can cause trouble if not used carefully.

Instead, I recommend using a “common” file that holds references to objects that are likely to be frequently wanted by one class or another. This can then be imported by such classes, and used from there.

Something like this:
(Also demonstrating the use of multiple Python-files.)

The “common” file. Let’s say that it’s called “Common.py”.

# I like to use a class with static members, but you can
# just store the variables at module level, if you prefer.
class Common
    myShowBase = None

A class that might want to use the ShowBase instance. Let’s say that it’s in “MyClass.py”.

from Common import Common

class MyClass():
    def __init__(self):
        Common.myShowBase.accept("space", self.someMethod)

    def someMethod(self):
        print ("Doing something!")

The “main” Python file.

from Common import Common
from MyClass import MyClass

class MyGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        Common.myShowBase = self

        self.myClassInstance = MyClass()
1 Like

Did you correctly create the corresponding folder hierarchy? Like this:

top-level folder/
    main.py
    myfolder1/
        __init__.py
        myfolder2/
            __init__.py
            characters.py

In the example that serega-kkz posted, both myfolder1 and myfolder2 need to be packages. To turn a regular folder into a Python package, it needs to contain an __init__.py module, which could be just an empty file.

EDIT:
OK, so the presence of an empty __init__.py module in a folder doesn’t seem to be necessary anymore in Python 3 to identify it as a package, my bad.

1 Like

Not too much difference, in fact it is the same.

This requirement is outdated for Python 3, everything works for me without this quirk.

2 Likes

As I said, I find inclusion of such things as parameters to get a bit unwieldy, in larger projects perhaps especially. Indeed, if I recall correctly it was for a similar reason that I started using a “common” file in the first place!

That’s interesting–I didn’t know that they’d changed that! That’s good to know! :slight_smile:

Ahh OK, I didn’t know this has changed in Python 3, thanks for the information :slight_smile: !
The tutorial I linked to doesn’t seem to mention this, which is why I wasn’t aware of it.

That makes two of us :grin: !

1 Like