Inherit poiter problem

Hi!!!
I have another question.
For example, I want create a NodePath called Ball.
A Ball has a float member called “life”. To refactor my project, I want to create a class called Ball derived from NodePath. For example:

class Ball : public NodePath {
float life;
public:
    Ball(NodePath model) : NodePath(model) {
        life = 10;
    }
};

I set up the collision between this object and another.
When i get the entry of collision, I have the method of CollisionEntry to get the NodePath. But i want have a Ball object not a NodePath to have the life member. My solution is the use the pointer which I cast it to (Ball*) with. when i have casted the pointer i can get my float.
The problem is my entry doesn’t return a NodePath* but a NodePath…
for example, this code doesn’t run correctly

#include <pandaFramework.h>
#include <pandaSystem.h>
#include <genericAsyncTask.h>
#include <asyncTaskManager.h>

#include <collisionTraverser.h>
#include <collisionHandlerEvent.h>
#include <collisionNode.h>
#include <collisionSphere.h>

PandaFramework framework;
AsyncTaskManager* taskMgr = AsyncTaskManager::get_global_ptr();
CollisionTraverser traverser;

class Ball : public NodePath {
public:
	float life;
	Ball () : NodePath(framework.get_window(0)->load_model(framework.get_models(), "egg_models/ball")) {
		life = 10;
	}
};


AsyncTask::DoneStatus run(GenericAsyncTask* task, void* data) {
	Ball* ball = (Ball*) data;
	framework.get_window(0)->get_camera_group().look_at(*ball);
	ball->set_fluid_pos(*ball, 0, 0, -0.4);
	traverser.traverse(framework.get_window(0)->get_render());
	cout << "ball1 life: " << ball->life << endl; // print 10 always
	return AsyncTask::DS_again;
}
// warinig at compile time: taking address of temporary
void decrement_life(const Event* ev, void* data) {
	CollisionEntry* entry = (CollisionEntry*) ev->get_parameter(0).get_ptr();
	Ball* ball1 = (Ball*) (&(entry->get_from_node_path()));
	ball1->life --;
}

int main(int argc, char *argv[]) {
	framework.open_framework(argc, argv);
	framework.set_window_title("Hello World!");
	WindowFramework *window = framework.open_window();
	window->enable_keyboard();
	
	CollisionHandlerEvent* eventer = new CollisionHandlerEvent();
	eventer->add_in_pattern("%fn-into-%in");
	
	Ball* ball1 = new Ball();
	ball1->reparent_to(window->get_render());
	ball1->set_pos(20, 20, 20);
	CollisionNode* cnode = new CollisionNode("ball1");
	cnode->add_solid(new CollisionSphere(0, 0, 0, 2));
	cnode->set_from_collide_mask(BitMask32::bit(1));
	cnode->set_into_collide_mask(BitMask32::all_off());
	NodePath node = ball1->attach_new_node(cnode);
	node.show();
	traverser.add_collider(node, eventer);
	
	Ball* ball2 = new Ball();
	ball2->reparent_to(window->get_render());
	ball2->set_pos(20, 20, 0);
	ball2->set_collide_mask(BitMask32::bit(1));
	
	taskMgr->add(new GenericAsyncTask("run", &run, (void*) ball1));
	framework.define_key("ball1-into-Sphere", "decrement life", &decrement_life, (void*) NULL);
	
	framework.main_loop();
  
	framework.close_framework();
	return 0;
}

How can I do it???

I hope that i have explained my problem well…

i try use GeomNode but when i run the program, it stops when loading the object…

#include <pandaFramework.h>
#include <pandaSystem.h>
#include <genericAsyncTask.h>
#include <asyncTaskManager.h>

#include <collisionTraverser.h>
#include <collisionHandlerEvent.h>
#include <collisionNode.h>
#include <collisionSphere.h>

PandaFramework framework;
AsyncTaskManager* taskMgr = AsyncTaskManager::get_global_ptr();
CollisionTraverser traverser;

class Ball : public GeomNode {
public:
	float life;
	Ball (NodePath model) : GeomNode(*((GeomNode*) model.node())) {
		life = 10;
	}
};


AsyncTask::DoneStatus run(GenericAsyncTask* task, void* data) {
	NodePath ball = framework.get_window(0)->get_render().find("**/ball1");
	framework.get_window(0)->get_camera_group().look_at(ball);
	ball.set_fluid_pos(ball, 0, 0, -0.4);
	traverser.traverse(framework.get_window(0)->get_render());
	cout << "ball1 life: " << ((Ball*)ball.node())->life << endl;
	return AsyncTask::DS_again;
}

void decrement_life(const Event* ev, void* data) {
	CollisionEntry* entry = (CollisionEntry*) ev->get_parameter(0).get_ptr();
	Ball* ball1 = ((Ball*)(entry->get_from_node_path().node()));
	ball1->life --;
}

int main(int argc, char *argv[]) {
	framework.open_framework(argc, argv);
	framework.set_window_title("Hello World!");
	WindowFramework *window = framework.open_window();
	window->enable_keyboard();
	
	CollisionHandlerEvent* eventer = new CollisionHandlerEvent();
	eventer->add_in_pattern("%fn-into-%in");
	
	Ball* ball1_mesh = new Ball(framework.get_window(0)->load_model(framework.get_models(), "egg_models/ball"));
	NodePath ball1 = window->get_render().attach_new_node(ball1_mesh);
	ball1.set_name("ball1");
	ball1.reparent_to(window->get_render());
	ball1.set_pos(20, 20, 20);
	CollisionNode* cnode = new CollisionNode("ball1");
	cnode->add_solid(new CollisionSphere(0, 0, 0, 2));
	cnode->set_from_collide_mask(BitMask32::bit(1));
	cnode->set_into_collide_mask(BitMask32::all_off());
	NodePath node = ball1.attach_new_node(cnode);
	node.show();
	traverser.add_collider(node, eventer);
	
	Ball* ball2_mesh = new Ball(framework.get_window(0)->load_model(framework.get_models(), "egg_models/ball"));
	NodePath ball2 = window->get_render().attach_new_node(ball2_mesh);
	ball1.set_name("ball2");
	ball2.reparent_to(window->get_render());
	ball2.set_pos(20, 20, 0);
	ball2.set_collide_mask(BitMask32::bit(1));
	
	taskMgr->add(new GenericAsyncTask("run", &run, (void*) NULL));
	framework.define_key("ball1-into-Sphere", "decrement life", &decrement_life, (void*) NULL);
	
	framework.main_loop();
  
	framework.close_framework();
	return 0;
}

You can’t call other functions in an initialiser, and you can’t just cast a PandaNode to GeomNode and expect it to work (in this case it crashes because it inherits from ModelRoot and not GeomNode).

Secondly, if you use this method, you’re copying the node to a new node instead of initialising the node. A much cleaner way to do it would be to let the Ball inherit from PandaNode and represent a dummy node (initialise it with : PandaNode(“ball”) or so), and in the constructor load the model and reparent the loaded model to the dummy node, by just calling add_child.

Thanks for your explanation!

But the main problem is how can i get the life method of Ball from CollisionEntry. Does a way exist that allows me this?

Exist the way of tag but with tag i store in a nodepath only string and the conversion of string to float or vice versa is more expensive…
IMHO The way of casting is the better, but cast what?
NodePath or ModelRoot?

i can edit previous code to use ModelRoot instead of GeomNode, but the program don’t load the object… I have used ModelRoot (const ModelRoot &copy) constructor called with ((ModelRoot) model.node() as parameter.

thanks for your patience! :slight_smile:

If Ball inherits from PandaNode, then you can get the collision entry node and walk up the scene graph until you find your Ball node again (you can use Panda’s typing system for easy type-checking, check out the classes in panda/src/skel for examples). Then, you can upcast it to Ball.

Keep in mind that if Ball inherits from PandaNode, it is now reference counted, which means that you must use PT()'s to refer to it.

And again, the way you’re doing it, you’re copying the node. I would recommend using the method I suggested.

But id i cast nodepath TO ball i loose the live value. Is it right?

Ball ball = (Ball) entry- >get_into_node_path();

another solution is create an class that represents a state of ball. Each nodePath has an I’d tag. Create a map string Id - state and use this to store anything … but it is ugly solution

You shouldn’t subclass NodePath. NodePath is just a container class; it’s not the thing itself; and it’s not meant to be subclassed.

Instead, if you must subclass, you should subclass PandaNode, as rdb suggested. This is the object that is actually stored in the scene graph, and there are already many different subclasses of PandaNode.

But you should understand that subclassing PandaNode (or other Panda objects) is a bit more advanced than simply using the Panda API directly. Unless you are very comfortable with C++ coding, I recommend not attempting to subclass any Panda objects. Instead, simply save pointers to your Panda objects in the conventional way.

David

Ops… now i understand…
Okinawa and sorry for my insistence!!
i load the mesh.
i create a new pandanode that has my float number. I create a nodepath passing my pandanode as parameter at the constructor and attach this to first nodepath .to get my float, find the nodepath that contains my pandanode and get it.

Or i create a nodepath that contains my pandanode and attach the mesh to it. In this way, to get my float, i get the parent and then the pandanode.

Is The second waybetter than first???

I think they sound about the same.

It’s to fast get_parent or find? The different is here
thanks for all :slight_smile:

get_parent() is much faster than find().

how does a PandaNode occupy in memory?

If there’s in the scene 1000 object with this situation, there’s a loss in performance?

I really don’t have a clear understanding of what you are trying to do here, and I don’t really understand what you are asking now.

If there’s some task you are performing 1000 times a frame, it’s probably a good idea to make sure it is a very efficient task, yes. Why not measure the performance to find out if it is acceptable?

David