I’ve been trying to learn Panda3d for a little while now but I just can’t seem to understand the way the engine is structured. Could someone clarify what are the differences and similarities of the following aspects:
initializing panda3d can be done in multiple ways:
from direct.showbase.ShowBase import ShowBase
and then create an object that inherits from showbase
from direct.showbase.DirectObject import DirectObject
objects should then inherit from DirectObject
what is the difference between those approaches, which one should be used, when to make a class inherit from either ShowBase or DirectObject, what is the difference between a class that inherits from ShowBase and from DirectObject, etc.
Furthermore i see that some code must be imported from panda3d.core, while other code must be imported from direct. Again, what is the difference?
Finally I don’t understand the difference between the ‘render’ object and ‘base’. Perhaps the better question is, what IS ‘base’?
Hope to hear from someone soon!
Generally, it is recommended to use the first method which is inherit from ShowBase. This is regarded as a more “proper” way to do it, though for quick scripts it can be handy to use the DirectStart method which works just as well, but might be more confusing for someone else reading the code, especially if they are not familiar with Panda. DirectStart is basically just creating an instance of ShowBase for you.
The panda3d module (panda3d.core, etc.) is where all of the C++ classes live. The direct module is where Python-only code exists.
render is just pointing to base.render, which is the default root NodePath of the scene graph. base is a global variable that is set when you create an instance of ShowBase, either explicitly or by running DirectStart. This also goes for other global variables such as taskMgr and so on.
The only thing that DirectObject provides is an ability to turn your class into an event handler, and be able to use self.accept and accept events. ShowBase also inherits from DirectObject, so you can use self.accept from your ShowBase derivative as well (or call base.accept if you aren’t interested in separate event handlers).
Thanks for the replies! they helped a lot.
So to recap, when designing a game it is best to have one ‘main’ object that inherits from ShowBase and (perhaps) different object(s) that inherit from DirectObject which require keyboard entry.
I have one small follow-up question: in the panda pace example the game is run by calling app.run(), since ‘app’ is a child of ShowBase I would expect that when using the DirectStart method one would have to call base.run(). Yet this is not the case, why?
I’m not sure what you mean. “base” refers to the ShowBase instance, no matter how you create it (even if you inherit from it, it creates a global “base” that you can use everywhere). So base.run() is the same as app.run(), assuming app is an instance of a class that inherits from ShowBase.
Simply calling the global function “run()” is a shorthand for calling “base.run()”. It is considered best practice to inherit from ShowBase and call run() on your ShowBase instance, however.
Maybe giving you the source code of DirectStart.py will help you understand what DirectStart is:
print 'DirectStart: Starting the game.'
from direct.showbase import ShowBase
base = ShowBase.ShowBase()
once again, thanks for the reply.
This anwsered my question, also many thanks for the extra info on the base global. I think i have a clear picture of what is going on now.