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:
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.
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()
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.
Not too much difference, in fact it is the same.
This requirement is outdated for Python 3, everything works for me without this quirk.
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!
Ahh OK, I didn’t know this has changed in Python 3, thanks for the information !
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 !