Collision Bitmasks?

Im starting to grasp the collision stuff. I was wondering if i needed to use the bitmask (whatever it is) if im using collision solids for my nodes… i dont understand what a bitmask is so i was wondering if it is neccesary :blush:

The manual goes into this extensively. But I guess it might be hard to understand if you’ve never used a collision system before that worked like this. (Making an assumption here!)

Collision masks are like filters. Basically masks filter. So, when the masks do not match, then Panda won’t even consider those objects for collision detection.

I think what really confuses people on this subject is the fact that Panda uses two masks for the same object in different collision situations, namely being considered as a source or destination. (I use another 3d engine and it uses the concept of accepting/sending collisions, and it’s similarly confusing to people new to the engine. But it’s the same mechanism as Panda’s system, merely expressed differently.)

FROM objects are moving objects. It’s usually as simple as that. In most collision systems, you break the problem of checking for two moving objects into checking for a moving object against a stationary one, then reverse the check. So, a FROM object in Panda terms is any object that is actively moving. You can think of it as the source object. Sometimes this is not obvious. Example: A ray or line segment.

The INTO object is something that is being considered against a FROM object. In other words, it’s the stationary object in that singular collision event, or the destination. Remember, though, that if both objects are moving, it might also be considered a FROM object in the next check, but this happens separately. And if the object is truly stationary, such as being terrain, it will always just be an INTO object.

setCollideMask is used to set the INTO collision mask on all nodes that are children of the node you give it. But if you want to get more granular than that, you will need to set the collision mask on the actual collision geometry/node directly using setIntoCollideMask and setFromCollideMask.

What you can be assured of is that any object you add to the collision traverser will be used as a FROM object, where as ones that are NOT specifically added will always be INTO objects. But a FROM object might also collide with another FROM object if the masks are set appropriately (in which it then becomes an INTO object for that particular moment).

You don’t have to use masks. By default, Panda considers all objects added to the collision traverser as FROM objects with any object in the scene graph containing collision solids as INTO objects. But if you’d like to filter collisions, then you will need to set the masks accordingly. And sometimes you need another layer of filtering on top of that, which is were the collision event/queue handlers come into play. (For example, bullets that can hit enemies and exploding barrels might need to be handled differently, code-wise.)

You can also filter collisions by name, at least if you use the event system. I seem to recall using a combination in the past- assign bitmasks to make doubly-sure I’m not registering any collisions between things I don’t want to search for collisions (more collision detection === more runtime), but use custom event and node naming to distinguish between different collisions I am looking for. I don’t recall the exact syntax, but there are some manual blurbs on setting up “%x-into-%y” named events where, e.g., %x and %y are determined by the actual colliding objects.

Yeah, I use events too. It’s flexible enough that you can use whatever method you want. If you don’t expect to use more than 32 classes of collidables in a single scene, or if you need a fairly straight forward collision hierarchy, then you can get away with just using bit masks.

The bouncing balls code sample I posted demonstrates using both. The smileys use collision masks to determine colliding with the ground and each other, then I set up an event which listens specifically for the smiley colliding into the ground and triggers an appropriate behavior. The nice thing about events is that you can get consistent behavior fairly easily without writing Python code, as you get a choice of how the events are fired, such as on-entry, on-exit, or on continuous contact.

I think I am having a similar problem. Or I am at least confused about a similar thing.

First off, do collision masks save processing time by preventing collision tests between non-intersecting bitmasks?

Using the event scheme doesnt save processing time though, does it? It just allows us to select which specific events we react to?

My problem is, I am spawning a lot of bullets, and I dont know how to stop them checking for collisions with each other. It must be wasting loads of processor resources. I only want them to hit walls and characters.

Any ideas?

Exactly right: setting your collision masks properly can save loads of processing time. Changing the events you listen for doesn’t save diddly.

To avoid your bullets testing for collisions with each other, set all of your bullets’ “into” collision mask to all bits off: BitMask32.allOff() or BitMask32(0). More generally, make sure that the “from” bitmask on your bullets only has bits in common with the “into” mask of your walls and characters.

David

I’ve always felt the term “mask” wasn’t accurate. Maybe “filter” instead? Anyway, the term “collision mask” is pretty much considered norm, but it helps to mentally think of it as the fist level filter used for considering collisions. If the masks don’t match, then the check never even occurs, even if the objects interpenetrate.

Events are useful if you want to tailor the reaction of your object to that collision. (Speaking of terms, better to think of collision events as “triggers.”) Since you can easily set up triggers on initial entry, repeating contact, or exit-only, this saves you time as you don’t specifically have to write Python code to check for these conditions.

You can also use this to establish many-to-one relationships, ie: I want an object that can collide with 4 other types of objects, but each collision should have a different behavior depending on that object.

However, though, keep in mind that once you’re in the event phase, you’ve already done the potentially-very-costly collision check. So, the first-order filtering of CollisionMasks comes into play here as a way to reduce load.

Ok, thanks. Thats pretty much what I thought.

I still have the problem then that my projectiles are all checking for collisions with each other.

I have looked at some of your youtube videos, and It looks like your Mecha game has projectiles similar to mine, do they check for collisions with each other? (cool looking game by the way!)

Thanks. :slight_smile: I will post some more videos here soon…

And no they do not. They are independent projectiles, currently implemented as line segments that adjust their tail length based on velocity. (Basically, I implement the concept of fluid pos manually, since that isn’t currently supported by line segments.) This is very stable, but kinda bogs down when there’s a lot of projectiles in play. However, it works well for my player weapons, which are intended to be slow moving and not very numerous. Most enemy projectiles move faster, so I fake 'em with single-shot rays and lerp intervals.

As for self-colliding bullets, pretty much what David said, you should make sure that the Into mask is set to nothing. Here’s code straight from my game:

        collisionNode = bullet.attachNewNode (CollisionNode ('bulletCN'))
        colSegment = CollisionSegment(0, -scale / 2, 0,
                                      0, scale / 2, 0)
        collisionNode.node().addSolid (colSegment)
        
        collisionNode.node().setIntoCollideMask (0)  # none, since this is a line segment
        collisionNode.node().setFromCollideMask (fromMask)
        
        self.cTrav.addCollider(collisionNode, self.cEvents)

fromMask is what my bullets will collide with, namely enemies, buildings, and so on.

It sounds like your From mask might be mixed up with the bullets themselves. Make sure they are assigned to a different bitmask as the rest of the objects they will possibly collide with.

Another way to think of From and Into is to consider it in terms of Sending and Receiving collisions. Into objects are receiving collisions from other objects, which might be sending collisions – if the masks overlap. But remember, an object’s determination as an INTO or a FROM is entirely relative. All objects are considered INTO objects by default, and will be checked (if, again, masks match). Only objects specifically added to the CollisionTraverser will act as FROM (aka sending) objects. But, that object will also be considered as an INTO object against other FROM objects, and vice versa – but only, once more again, if your masks match. This merry little dance continues until everybody has had a possible chance to collide with everybody else.

This needs some pretty pictures or something in a way of explanation. It’s one of the most-asked questions about Panda collisions. Heck, it confused me at first, because setCollisionMask() is actually a shorthand for setCollisionIntoMask().

Thanks guys, that helped a lot, I think I have my collisions pretty much sorted out now. Each character has a ray that is used for the collisionHandlerGravity, a sphere for the collisionHandlerFluidPusher and a capsule which is used as a hitBox for collisions with bullets.

There is a mask common to the ray, sphere and terrain

And then there is a mask common to the one team’s hitBoxand other team’s bullets and visa versa. And of course the bullets can impact the terrain.

base.maskTerrain       = BitMask32(1) # 0000 0000 0001
base.maskHitBoxes1     = BitMask32(2) # 0000 0000 0010
base.maskProjectiles2  = BitMask32(3) # 0000 0000 0011
base.maskHitBoxes2     = BitMask32(4) # 0000 0000 0100
base.maskProjectiles1  = BitMask32(5) # 0000 0000 0101

My “only” problem left is how to do something to a character when he gets hit by a bullet. It is easy to delete the bullet when it hit something, because the each bullet has an ID and generates the following pattern on impact

#self.ID is a int that increments with each bullet fired
self.collHandEvent.addInPattern('impact_'+str(self.ID))

But how do I do something to the unlucky recipient of the lead? I can use entry.getIntoNode() In the bullet’s collision event to get which hitBox was hit, and then use

 messenger.send('bullet into'+str(entry.getIntoNode()))

The character would have to be listening for events that refer to its hitbox

Does my plan make any sense?

PS: sorry if I’ve been rambling… I was totally blank when I started typing. The messenger thing just came to me now :confused:

I like your message sending idea. Personally, I do something a bit more convoluted.

I create a Python tag on my collision nodes that “point” back to the python instance that encapsulates it. I then define a handleCollision method in that class which will process the requested collision type.

So in my code, I do in my event:

  collisionNode = entry.getIntoNode()
  parent = collisionNode.getPythonTag ('pythonObject')
  parent.handleCollision(entry, entry.getFromNode())

However, I admit I dig your idea of having those objects register events and then just use the messaging system. This would dovetail in better with my component-based architecture. Thanks for the idea. :slight_smile:

Ok, well in that case I will have to give the messenger a go :slight_smile:

(At least one of us must be up at weird hours, 'cos no matter what time of the day I post, you are always back with an answer in moments, and you are pretty much on the other side of the world :smiley: )