Click or select an object

The following is within a mouse event, and occurs when a left click is detected. It seems to work, even “Humk?” is being printed, but obj.set_color() causes an assertion fail: !is_empty()

After having googled and tried everything, can anyone help me with this one?

 else if(self->LMBclick)
{
    
    //PT(MouseWatcher) mouseWatcher;
    PT(CollisionRay) pickerRay;
    CollisionTraverser myTraverser = CollisionTraverser("ctraverser");
    PT(CollisionHandlerQueue) myHandler;
    PT(CollisionNode) pickerNode;
    NodePath pickerNP;
    
    pickerNode = new CollisionNode("mouseRay");
    pickerNP = camera.attach_new_node (pickerNode);
    pickerNode->set_from_collide_mask(GeomNode::get_default_collide_mask());
    pickerRay = new CollisionRay();
    pickerNode->add_solid(pickerRay);
    myHandler = new CollisionHandlerQueue();
    myTraverser.add_collider(pickerNP, myHandler);
    
    
    LPoint2f mpos = mouseWatcher->get_mouse();
    pickerRay->set_from_lens(self->Window->get_camera(0), mpos.get_x(), mpos.get_y());
    
    myTraverser.traverse(self->Window->get_render());
    
    NodePath obj;
    if(myHandler->get_num_entries() > 0)
    {
        myHandler->sort_entries();
        obj = myHandler->get_entry(0)->get_into_node_path();
        obj = obj.find_net_tag("clickable");
        //pickerNP.find_net_tag("clickable");
        //pickerNP.set_color(255, 0, 0, 255);
        //pickerNP.show();
        obj.set_color(255, 0, 0, 255);
        std::cout << "Humk?" << std::endl;
    }
    
    std::cout << "LMB Click: " << mpos.get_x() << "," << mpos.get_y() << std::endl;
    self->LMBclick = false;
    
}

With this line:

obj = obj.find_net_tag("clickable");

You’re trying to find a subnode of the into CollisionNode that has the clickable tag, but if there is no such node under the CollisionNode in question, then it will return an empty NodePath, which cannot be manipulated because it does not point to any node. Use obj.ls() to find out what is actually underneath (and obj.reverse_ls() to find out what is above it).

By the way, set_color accepts values in the 0.0-1.0 range, rather than in the 0-255 range.

The objects are white cubes, which ultimately will be characters in a RTS-style game. And later buildings will need to be clickable too. I did not set any collision detection on these objects, because obviously I will not need it in my game.

How should I fix this? Do I need to give these objects collision detection? Is there another way to find them?

They do have the “clickable” tag, but i understand they are not at the proper place in the node graph…

NodePath cube = PandaWindow->load_model(Framework->get_models(), "models/cube.egg");
    cube.reparent_to(PandaWindow->get_render());
    cube.set_pos(Random->Normal(10),Random->Normal(10),1);
    cube.set_tag("clickable", "2");

It looks like the problem is that your tag is set on the “into” NodePath itself, and not on one of its ancestors (which I think that “findNetTag” searches). That is, looking at the description of “findNetTag” in the API, it seems that it doesn’t search the node on which it’s called–only the ancestors of that node.

Thus, if you were to instead call “getTag” on the “into” NodePath, it should return your tagged value.

(Note that may be a good idea to check whether the tag is present, either by first calling “hasTag”, or by checking to see whether the result of “getTag” is not empty. That way if you have any untagged models (background objects, perhaps), clicking on them shouldn’t run into similar issues.)

It might also be worth noting that collisions with visible geometry are not as efficient as collisions with dedicated collision-geometry, if I’m not much mistaken.

If your scene is going to be very simple, this might not be a problem. However, if your scene becomes more complex and you start to encounter performance issues (or if you’re encountering such issues already), and if profiling indicates that the problem lies with your collisions, then it might be a good idea to use collision geometry for the selection of objects.

Okay I kind of give up now. I’ve spent like 3 days on this one. I’ve looked up gazilion of examples online and can’t find any difference with my code and what others have.

:sob:

Hmm… Have you tried commenting-out your tag-finding and colour-setting code (so that they don’t trip up the following), and then calling “obj.ls()” to see what your “into” NodePath is, and what children it has–and thus which of them, if any, has your tag?

And, just to check, did you try my suggestion two posts above this one?

[edit] Thinking about it further, I think that you should be correct in using “find_net_tag”, rather than “get_tag”. However, it’s still worth trying the latter, just in case–and my suggestion of calling “ls()” stands. Indeed, it might also be worth printing out the “into”-NodePath’s parent, and perhaps its parent’s-parent, to see what they are and whether they have your tag.

Ah! Thanks for that Thaumaturge, I found the issue right away using .ls(). I realised I was clicking on something called “cylinder” instead of my “cube”. I was using the environment from the Hello World demo, just so I had something to look at while I was testing all the features and algorithms that I need, instead of a dark grey background. Turns out that the thing probably has some transparent geometry around it, I was unknowingly clicking on it instead. The cube turned red (obj.set_color(…)) as soon as I removed the environment. Talk about a waste of time!!

Sorry that I didn’t comment on your prior post, although i did try/check everything in there.

get_tag() returns a string, specifically the value of the tag, which I don’t care about, whereas find_net_tag() returns a NotePath. As explained in the manual, the collision occurs on the surface of the geometry, and that’s what you get, whereas you actually want a pointer to the underlying object, which you can find using that tag (not the only way, but seems easy and generic enough to me).

And of course, I will check that it’s not is_empty(). I just didn’t care for the tests as it tells you in the console window that an error occurred.

Collision with geometry are not as efficient as dedicated collision geometry? Well, the later is obviously better for collisions which are being checked for every frame world wide, however the player is unlikely to click often enough as to slow down the game, but I’ll keep that in mind if optimisation is required later.

Ah, I’m glad! :slight_smile:

Not a problem!

Ah, I see better what you’re doing, now, I believe. That makes sense, I do believe!

(And I’m surprised to now find that the C++ side of the engine doesn’t have a feature similar to the Python side’s “setPythonTag” method, which allows directly referencing a given object. Ah well, what you have works.)

Good good; that makes sense. As long as you do have it in mind to do so! :slight_smile:

By a long shot, as I understand it!

Still, if it doesn’t cause problems for you then it might be fine in your case.