How to structure a project

Hi!
I’d like to start to develop a little project with Panda3d, I love this game Engine!

But, after reading the documentation, i don’t understand how can i integrate the engine’s class with the game’s concept.

For example, a shooter needed to create a world, a player and the monsters. The player and a monster have a life, a velocity etc… This information is of the character. Reading the documentation, i know there is setTag method to set a tag to a nodePath, but… if i like to add more complicated info, how can i do it?

For example

class LivedCharacter {
public:
 int life;
 int get_life() { return life; }
 void damage(int d) { life -= d; }
 int is_alive() { return life > 0; }
}

How can i integrate this with panda3d?
Can i derive from PandaNode to add the infoNode to render tree?

Thank you for supporting

It’s possible to derive from PandaNode in the usual way and add whatever methods and data members you like.

However, it may be easier (and better) not to attempt to do this, but instead to maintain your own data structures independently of Panda, and simply store a NodePath or a PT(PandaNode) within your class that references the Panda component of your character.

This is a classic object-oriented design decision: should you use an “is a” or a “has a” relationship? I think it is better in general if you use a “has a” relationship for this sort of thing: your object “has a” PandaNode, not your object “is a” PandaNode.

David

Thank you David for your answer

I’d like to understand better what the ‘is’ style means…

For example I have a FirstPersonShooter, all enemies have a live. To represent this scenario, i think to create a class in which there’re the “game” logic.

During the implementation, How can i integrate my class with the framework? (not integrate the framework with my class)

I think the facade pattern, but this means to build a very large class…
Indeed, if i integrate the framework with my class, this problem doesn’t exist, but it seems very ugly approach

I believe in this context, “is” refers to subclassing a Panda class.
“has” would be to make your own class and have it reference an instance of a pure Panda class.

I personally use the “has” methodology. For example my Level class has a “node” attribute which points to the root NodePath for that level’s geometry. Each character has a “node” attribute which points to the Actor. This is a much more straightforward way to go about structuring your game than subclassing since you do not need to concern yourself with the structure of NodePath, for example to avoid accidentally redefining an attribute.

Thank for your answer
But when i need to interactive with the framework (for example when you need to add a new monster), how can i do it?
There’s a game’s component that has a facade for interactive with framework.
For example

class Panda3dFacade {
   PandaFramework* fr;
public:
    void addMonster(Monster* m) {
        NodePath p = getMonsterModel();
        m->setNodePath(&p);
        p.reparent_to(getRoot());
    }
    void removeMonster(Monster* m) {
        NodePath* p = m->getNodePath();
        if (p != NULL)
            p->remove_node();
        m->setNodePath(NULL);
    }
}

How do you find this?
Obviously Monster could be replaced with a generic renderable object

First, I’d suggest that “monsters” might benefit from a “has-a” structure themselves: the “Monster” class has a NodePath, etc.

That said, I think that I’d likely have my “World” class (or whatever it is that manages monsters) keep a list of monsters, rather than a pointer to a single monster.

And the asynchronous tasks?
For example the hero, when he isn’t under attack, heal himself. How do you build this scenario?
And if I have a lot of tasks?

Thank for this discussion!

First of all, do you mean “tasks” in the sense of “things to be done”, or Tasks in the Panda sense?

I suppose that I might model it via a simple state machine: when attacked, the player enters the “attacked” state, which automatically cools down after a certain amount of time; subsequent attacks reset this cooldown. The “attacked” state transitions to the “healing” state, in which the character heals himself.

I’m not sure of what you’re asking. Are you asking whether a large number of tasks is viable? ^^;

Task as a function that must be recall after some seconds, like generate some enemy or update game’s property.

The following text deals with the Python side, but the ideas can be used in C++ the same way.

Panda has three kinds of changing the behavior of actors:

  • Intervals are the easiest ones. You simply tell what things should be done. You can also stack those or run them in parallel. There’s a nice manual page about this.

  • A Task (in Panda terminology) is a function that is run every frame or any fixed time period. You can make your actor class add the task to a global task manager or handle its own manager (which uses the global one as well, but with additional management). You can freely have multiple tasks within one class and you can have many of them. Stopping a task is possible from inside the task function or from outside. This is the most used technique to implement any logic in Panda, I think. It’s also the foundation of many Panda internal classes (e.g. Intervals). If you have experience from some other game engines, imagine the tasks as items that are looped and called from the main loop.

  • Events are rather hard, less documented and using your own might interfere with Panda’s events, which are nowhere documented. You surely have noticed, that you can call accept(“space”, myFunction) on ShowBase, DirectObjects and other classes that inherit or proxy the Messenger class. You can also send events using that class and you can even have multiple event systems running in parallel. Imagine this:
    if health < LOW_HEALTH: messenger.send(“health_low”) … avatar.accept(“health_low”, fsm.flee)
    This allows you to very loosely couple your components, but the overview gets lost quickly, too.

I think a task as panda task: I’d like to update a game property after fixed time.
For example is the hero has a health item, his life is incremented of 5pt every 2second.
This is an example of task.
Where you put the logic of the adding/removing of task?

A proxy?
Thanks