CollisionHandlerEvent: NodePath names?

I want an event to trigger when my player’s sphere collides with an npc’s sphere. So both Player and NPC are classes in my game, each having a “root” nodepath.

According to the manual, this is how to set player to be a from and npc to be an into.

handler.addInPattern('%fn-into-%in')
handler.addAgainPattern('%fn-again-%in')
handler.addOutPattern('%fn-out-%in')

But what if my NodePaths in the NPC class all have the same name? I mean should I use a random number generator or something to make sure they all have different names? NodePath.getName() wouldn’t help as you can have NodePaths with the exact same name, no number or anything gets appended to the end of the name to differentiate them.

Even with random numbers there is a chance of repeating names. I could have a global index variable which gets incremented by each NPC instance and added to the name, but that doesn’t seem like a good design.

Hm, how about using Python’s id() function?

>>> class MyClass:
...     def __init__(self):
...             self.name = id(self)
...
>>> a = MyClass()
>>> b = MyClass()
>>> a.name
35510672
>>> b.name
35510712
>>>

That will not work reliably. Two NodePaths pointing to the same node will not necessarily be the same object.

“myNodePath.node().this” is as far as I know the only unique number associated with a node.

OK, thanks.

But overall is this a smart way to use CollisionHandlerEvent?

First you should understand the difference between NodePath and PandaNode. A node can have a name. A node path does not have a name. NodePath.getName() is just a shortcut for calling NodePath.node().getName(). Keep in mind that you can have many handles (node paths) to one node. So even if you give each name a unique name then you can have many node path objects which have the same name. However, this is no problem, since they all point to the same node.

Why? Just because it is “global”? Every database has so called “key generators” to create unique keys, often in sequential order. A sequential key generator is nothing but a global index variable inside. So all databases would have a bad design in your opinion?

If you want a fancy way to create unique id’s I recommend using UUIDs. UUIDs are a more advanced way of generating unique identifiers, and used even inside operating systems to identify things. Just open the Windows registry.

import uuid
name = "character number %s" % uuid.uuid1() # or use uuid.uuid4() if you worry about privacy...

I’m asking a question, not sharing an opinion.
I thought it would be a bad desing to have a global variable for an index, and increment that index in all the class instances, if there was another way.

Well a random number generator doesn’t care if the number has appeared before, at least Python’s random module. While objects are guaranteed to not have the same id (during their lifetime), ex. when calling “id()”, and I guess it’s true for “node.this” as well.

But yeah, I now the chance of random.randint() giving the same number is very very low. But still makes me feel uncomfortable.

I don’t see a question mark at the end of your sentence. I think we both agree that you are not just asking a question, but also provide context for answering your question, and this context includes your personal opinion.
It’s just fair that I am asking for more details here, in order to find out if global variables are a hard limit for you. This would limit the number of possible solutions.

No, you are not guessing right. Consider what is happening under the hood: You only see the Python objects which get automatically created for the underlying C++ objects, and it is possible that the wrapper layer creates several Python objects for the same C++ pointer:

np = loader.loadModel(...)
n1 = np.node()
n2 = np.node()
print n1 == n2  # True, because comparison is implemented and compares the wrapped pointers.
print n1 is n2  # False, because we have two different objects
print id(n1), id(n2)  # Two different objects...

Stop guessing and verify your ideas before posting them here. It’s not that difficult, as you can see. If you can’t verify something, then make it a question (a sentence which is ending with a question mark!).
If people always have to verify your claims or spend effort on persuading you that your ideas are wrong then you will soon end without anybody wanting to answer your questions.

But yeah? Is this in response to anything I have writen or someone else has written? I have been talking about UUID, not random numbers. uuid.uuid is
guaranteed to be unique.

Can I ask why you are so rude? This isn’t the first post I see you being harsh to others as if they are fighting you.

To me it wasn’t clear whether you were replying to the idea of using random numbers or storing an index (id).
As for why I thought storing an index was a bad idea was simply that I would need a global variable accessed by all the instances and modified. And if Panda/Python already stored an id like that, it would be pointless to store your own. That’s all I meant.

Maybe, but that’s what I am doing. In my game, both the ships and their projectiles have a ID assigned to them when they spawn.

This ID is then applied to the collision node of ships (and projectiles), like:

self.model = loader.loadModel(...)
self.cnode = self.model.attachNewNode(CollisionNode('cnode'))
self.cnode.setTag("shipid", str(self.id))

Upon collision (I use a Queue, not Event) in the handler:

for i in range(self.colls_handler.getNumEntries()):
	fromnode = entry.getFromNodePath()
	intonode = entry.getIntoNodePath()
	# "sourceid" tag was added in projectile spawning function
	fromshipid = int(fromnode.getTag("sourceid"))
	intoshipid = int(intonode.getTag("shipid"))

As a source if you can use the ID of the ship that spawned the projectile or apply the ID of the projectile.

I can answer this question, if you really want to know. I hope you are not too much offended - keep in mind that you are asking me for my personal view. I will send you a PM.

By the way, I have not been reading your post careful enough. id() is not unique. But np.node().this is more-or-less unique, since you get the C++ pointer (memory address) of the PandaNode this way. However, if a PandaNode is destroyed and another PandaNode created afterwards it might be that the second node has the same memory location as the first one used to have.

I generate unique ids like this:

import itertools
new_id = itertools.count().next

print new_id()
print new_id()
print new_id()
print new_id()

So instead of a global variable, I use a coroutine. It’s a little more resistant to coding errors. Nothing revolutionary, just a neat way of doing it. If you need to save and reload the game, you can store the last created id in the saved game, and reuse it to redefine new_id :

game.last_id = new_id()
game.save()
# Life happens.
game = Game.load()
new_id = itertools.count(game.last_id).next