Identifying objects when colliding

Hi for all

I have collision detection in my game. I have 3 plates. Two of them have this bitmask set of from and into mask:

self.Prato1.SetFromMask(-1)
self.Prato1.SetIntoMask(1)
self.Prato2.SetFromMask(-1)
self.Prato2.SetIntoMask(1)

These function are described below:

   def SetFromMask(self, IDMask):
      if(IDMask == -1):
         self.PlateCollision.setFromCollideMask(BitMask32.allOff())
      else:
         self.PlateCollision.setFromCollideMask(BitMask32.bit(IDMask))

   def SetIntoMask(self, IDMask):
      if(IDMask == -1):
         self.PlateCollision.setIntoCollideMask(BitMask32.allOff())
      else:
         self.PlateCollision.setIntoCollideMask(BitMask32.bit(IDMask))

And this is the way that I insert the collision type in them:

bounds = self.PlateModel.getChild(0).getBounds()
      self.PlateCollision = CollisionNode('Plate')
      #CollisionPolygon(Point3(0, 0, 0), Point3(0, 0, 1), Point3(0, 1, 1), Point3(0, 1, 0))
      self.PlateCollision.addSolid(CollisionSphere(bounds.getCenter(), bounds.getRadius()*0.5))

The two plates uses this function to print their ID

def HandleCollision(self, entry):
      print str(self.IDObj)

the third, that is the collider have this definition

BeeNodePusher = CollisionNode('BeePusher')
       #CollisionSphere(bounds.getCenter(), bounds.getRadius()*0.5)
       BeeNodePusher.addSolid(CollisionSphere(bounds.getCenter(), bounds.getRadius()*0.5))
       BeeNodePusher.setFromCollideMask(BitMask32.bit(1))
       BeeNodePusher.setIntoCollideMask(BitMask32.allOff())
       self.BeeNodePathPusher = self.Bee.attachNewNode(BeeNodePusher)
       self.Collision.CollisionPusher.addCollider(self.BeeNodePathPusher, self.Bee)
       BeeNodeCollision = CollisionNode('Bee')
self.Collision.CollTraverser.addCollider(self.BeeNodePathPusher, self.Collision.CollisionPusher)

The collision works very fine. But now I explain my problem. If I collide in any of the objects the ID’s of both are printed. What I want to know is:
How can I recognize two or more objects from the same type? Each of them are instantiated separately, so why this behavior is occuring?

Thanks for the support again

A bitmask is different from an ID.
You now specify a value -1 and a value 1. The setFromMask and setInputMask wants a bitmask, so (i think!) -1 is evaluated to 11111111111111111111111111111110 and 1 is evaluated to 10000000000000000000000000000000.
In both cases, the first bit is ON, so they both will be colliding. You can create a bitmask with just the nth bit switched on by doing BitMask32.bit(n-1). Like this:

self.Prato1.SetFromMask(BitMask32.bit(0))
self.Prato1.SetIntoMask(BitMask32.bit(1))

I could be totally wrong, this is just my perspective on the problem.

I think that’s not correct.
If you look at this thread: discourse.panda3d.org/viewtopic.php?t=2508
you’ll notice that for the objects that will suffer the collision all of them have a BitMask32.bit(2) in the setIntoCollideMask’s function. I’ve tried to do some thing like this but the problem persists.
I can put the whole code in here for clarification, are you want?
The collision detection is driving me crazy

Of course both get printed, since they listen for EXACTLY the same event, right ? And you simply print the instance’s ID, regardless the entry passed to HandleCollision.

  1. If you take advantage of entry, you would get the correct instance :
print entry.getIntoNodePath().getParent().IDObj

Every plate instance would print that out. Don’t say this is a problem. This is really suitable for “team” (multiple instances) respond, i.e. “Bos just got hit, help him everybody” type respond.

  1. If you don’t need that, there is another way, the correct way, individual respond, “I got hit, run away” type respond.
    Say your CollisionHandlerEvent’s in-pattern is “collide-%in”, %in would be filled with “into” CollisionNode’s name.
    So each plate instance must listen for specific event, like this :
self.accept('collide-Plate'+str(self.IDObj), self.HandleCollision)

Append the ID to the name of CollisionNode

self.PlateCollision = CollisionNode('Plate'+str(self.IDObj))

Thus each instance responds to collision which involves itself only.

ynjh_ho, I was searching for you to talk about your solution in your post I’ve put here to illustrate my problem.

you’ve said for me to do this:

self.accept('collide-Plate'+str(self.IDObj), self.HandleCollision)

Look at my method in the plate class that I call in each instance of the class:

def AcceptHandler(self):
      PlatePath = self.PlateModel.attachNewNode(self.PlateCollision)
      PlatePath.show()
      self.accept('collide-Plate', self.HandleCollision)

Aren’t they the same? If I insert the ID in the accept, it will be recognized individually? Only this? I cannot believe if I insert the ID in the accept the object will be able to recognize individually.
I’m question this because in my understanding of panda’s collision detection the engine can recognize each object inserted, not all of them when I collide to one of them and that have same bitmask collision. In this way, it seems that the engine forces you to insert a bitmask for each object, even if the objects are all equal.
In my opinion, the panda’s method to recognize all objects like you said, is suitable for “team” but not for individual object. In the docs this explanation you’ve said to me(suitable for “team”) is not there. If you follow the whole documentation many doubts aren’t answered.
If you don’t mind you can explain a little more about individual collision among various same objects detection in panda?

There is nothing wrong with P3D’s collision engine. Seems that it’s you haven’t gotten enough grip on Object Oriented Programming. No offense, correct me if that’s wrong.
And I believe Josh Yellon writes most of the manual with hope that the user already familiar with OOP, so there are only the basic parts.

It depends how you want your object should respond to collision. Your problem is collision listening.

SCENARIO 1 : team respond
Each instance must listen to event_A, in order to maintain teamwork against situation_A.

  1. every instance’s CollisionNode is named “Plate”
  2. every instance accepts “collide-Plate”
    If there is bee hits plate1 (say ID=1), the generated event would be “collide-Plate”.
    What objects are accepting “collide-Plate” ? Both plate1 and plate2. So plate1’s HandleCollision would be called, as well as plate2’s.

SCENARIO 2 : individual respond
Each instance doesn’t care of other instances’ collision, so only need to listen for collision against itself. Then you should personalize event’s name, say “collide-Plate1”, “collide-Plate2”, “collide-Plate3”.

  1. every plate instance’s CollisionNode is named “Plate”+str(IDobj)
  2. every plate instance only need to accept “collide-Plate”+str(IDobj) event
    If there is bee hits plate1 (say ID=1), the generated event would be “collide-Plate1”.
    What objects are accepting “collide-Plate1” ? Only plate1 (plate2 accepts “collide-Plate2”). So only plate1’s HandleCollision would be called.

Conclusion :
Based on your needed scenario, it’s your responsibility to manage which object must listen to which event. Bitmask is only used to build a list of possibly colliding object.

The engine can recognize each object inserted, not all of them when I collide to one of them.

Actually it gives the entry to your method HandleCollision. It’s up to you to decide what to do about it.

Appending the ID is the most clean approach. But sure you can do the dirty way :

def HandleCollision(self, entry):
    if entry.getIntoNodePath().getParent()!=self.PlateModel:
       print 'Other plate was hit. Why should I care ?'
       return
    print str(self.IDObj)

No matter man. Ok, it becomes much more clear now. Your explanation clarifies a lot now.
My background is totally C++. Python and Panda are very new to me. My code is object-oriented. And I believe the Josh has the best will when he writes the manual. But it doesn’t mean that somethings like your explanation didn’t pass for him. There are things that are not so deductible, again, like your explanation.
In my opinion the docs needs an update.

Thanks for you and pro-rsoft

Ok i think there is confusion between 2 differents things.

A)The bitmask is not an ID .
the bitmask is used to limit the number of collision check the engine perform .It’s for optimization purpose.
If you set the Bitmask to allOn (11111111111111111) it may collide with everything so the engine will check for collision with every object in the scene.
If you set the Bitmask to 10000000 it may collide only with object that have a 1 in first position, so the engine will check for collision only with object that have a bitmask with 1 in first position.

B) The messenging system.
When you declare self.accept(“Event A”) you tell your object to be “activated” when such an event is thrown.
Let’s say Object A accept “Event A” and Object B, and C accept “Event B”
If “Event A” is fired, only Object A will be activated and can react
If “Event B” is fired , both Object B & C will be activated and can react
if "Event " is fired , none will react.

Now in your current setup.
You configure the Collision System to say a generic Event every time
“CollidePlate”
And you Configure each plate to accept “CollidePlate”
So each time there is collision with any of the plate, the Collision System send the event “CollidePlate” and since both plate are allowed to react on the Event “CollidePlate” then both plates do react and print their ID.

=> in fact you configured all plates to print their ID every time a collision is detected with any of the plate.

Now, if you want to distinguish between the different plates when a collision occurs , you have two solutions:

Choice 1: more usual.
As explained, you configure the Collision System to send a different event for each plate where collision is detected.
So you configure your Collision System to send “CollidePlate-%in”
and Plate1 to accept “CollidePlate-Plate1” and Plate2 to accept “CollidePlate-Plate2”
This way, when Plate1 is collided, the Event CollidePlate-Plate1 is sent by the system. In this case, only Plate1 can accept this Event and only plate 1 does sent it’s id.

Choice 2:
You keep the generic event in the Collision System and the Plate still accep the Generic Event “CollidePlate”.
In this case, eachPlate must use entry_ID=entry.getIntoNodePath().getParent().IDObj into self.HandleCollision to check if entry_ID is equal to their own ID.
If yes, then the Plate can print it’s ID.
If no, then it means the Plate reacted to a collision with Another Plate so it must not print it’s ID.

That’s true. In my opinion right now the documentation/examples are what need attention more than anything else.

guys, it works. Thanks for all the replies. And if all of them notice, T Rex agrees with my opinion that the docs needs to be updated. I think that most experieced panda programmers should be a contribution un the docs.

Alex