The Panda3D engine was mainly designed to be controlled by Python scripts to hide away the complexities of handling and rendering a 3D game world. This allows us to concentrate on creating game scenes and gameplay without having to think about any low-level implementation issues. Many of these have already been solved by the Panda3D developers and are implemented in a whole set of libraries written in C++. When working with Python Panda3D's API nicely wraps their functionality, but we may also use these libraries directly from our own C++ code if we prefer to use this language instead of Python.
If you haven't yet, please read the recipe Configuring Visual Studio 2008 to work with Panda3D found in Chapter 1 prior to starting this one. The following steps assume you know how to get a Panda3D project started in Visual Studio 2008 or Visual C++ Express 2008. Both editions can be used for this recipe. For the sake of readability, this recipe will refer to both of them as Visual Studio 2008.
These tasks will show you how to create a scene using the C++ programming language:
main.cpp
.#include <pandaFramework.h> #include <pandaSystem.h> #include <animControlCollection.h> #include <auto_bind.h> PandaFramework framework; int main(int argc, char* argv[]) { framework.open_framework(argc, argv); WindowFramework* win = framework.open_window(); NodePath camera = win->get_camera_group(); NodePath teapot = win->load_model(framework.get_models(), "teapot"); teapot.reparent_to(win->get_render()); teapot.set_pos(-5, 0, 0); NodePath panda = win->load_model(framework.get_models(), "panda"); panda.reparent_to(win->get_render()); panda.set_pos(5, 0, 0); win->load_model(panda, "panda-walk"); AnimControlCollection pandaAnims; auto_bind(panda.node(), pandaAnims); pandaAnims.loop("panda_soft", false); camera.set_pos(0, -30, 6); framework.main_loop(); framework.close_framework(); return 0; }
In this recipe, we are using the PandaFramework
class, which acts as a wrapper around Panda3D's core classes to form an application framework. To get our application started, we need to initialize our global instance of PandaFramework
and open a window. For convenience, we also get a reference to the default camera, so we don't need to call win->get_camera_group() every time we want to modify the camera.
Loading the teapot and panda models and adding them to their positions within our little scene looks nearly the same as in Python, with one exception—that strange call to framework.get_models()
. This method returns the root of scene graph, which is not rendered, but instead serves as a scratchpad area for model loading. This is passed to the load_model()
method as the parent node that the model will be attached to and may seem a little overly verbose in this sample. In fact, we could pass win->get_render()
as the parent node and drop the reparent_to()
call. But in practice, where you might not add a model to the scene directly after you loaded it, the purpose of this scratch scene becomes more evident. In real world projects, hundreds of models are preloaded for the current level, with this scratchpad area removing the need to keep hundreds of NodePath
instances around. Instead, the temporary scene is queried for the needed model, which then is reparented to its place in the rendered scene.
Loading and playing animations also works differently than what we know from Python. Instead of an explicit method for loading animation data, we use load_model()
to load the animation and make it a child node of the panda actor. We then call auto_bind()
to fill an AnimControlCollection
and bind the animation data to the panda actor. Note the animation name used for starting the loop—this is the animation name found in the panda-walk
file defined in the art tool used to create the animation.
Lastly, we set the camera position and start the main loop, from which the program will only return if the program is terminated. At this point, the close_framework()
method is called to properly clean up.