Best Suited Collisions

Hi Guys

I am a little confused as to which collision type to use for my game.

The game is going to be a 8-direction game in the spirit of The Chaos Engine. I easily changed the roaming ralph example to the control type I want, and included a very basic level.

The collision ray method from Roaming Ralph is ok, but the character can “jump” up walls, and cant walk under things. Im sure I could fix that, but the manual does warn that the RR example is not very efficient. I have searched the forums high and low, and cant find a definitive answer on what method would be best for me.

Any suggestions?

I like some aspects of the “gravitywalker”, but I dont think it can be easily changed to 8direction control.

enable the collision nodes to see where they check for collisions, if the collisionray starts 10 units above the character he’s going to “jump” onto any wall that’s up to 10 units above the char. also if you have a additional collisionsphere that should check for wall collisions it’s not doing anything if it’s above any wall you want to collide with.

here’s a snipplet from my collisionhandler (only the wall collider not the floor handler)

    wallPusherCNode = CollisionNode('pusherCNode')
    cs = CollisionSphere(0, 0, 1.0, 0.5)
    wallPusherCNode.addSolid(cs)
    wallPusherCNode.setFromCollideMask( TERRAIN_COLLISION_BITMASK )
    wallPusherCNode.setIntoCollideMask( EMPTY_BITMASK )
    self.wallPusherNode = NodePath(wallPusherCNode)
    self.wallPusherHandler = CollisionHandlerPusher()
    self.wallPusherHandler.addCollider(self.wallPusherNode, self)
    self.wallPusherHandler.setHorizontal(True)
    if DEBUG >= 3:  # see where the collider is
      self.wallPusherNode.show()
    base.cTrav.addCollider(self.wallPusherNode, self.wallPusherHandler)
    self.wallPusherNode.reparentTo(self)

The warnings are about how RR handles the level collision geometry. It simply uses the same geometry for visualization as the collision geometry. So Panda3d is doing ray/triangle checks for all of the triangles that are found in that level. (I think it’s around 2-3k triangles total.) While you can get away with this for small levels or simple scenes, you’ll find that your performance will nosedive when you expand the level’s size and add enemies, bullets, powerups, etc. That’s because each ray collision must occur with all X triangles of that level.

Most of the ways around this are based on the simple idea of making the coldet system do less work by dividing up the number of solids it must run a check against. So, your level is split into a hierarchical data structure that limit the number of collisons-per-region which must occur. (Octrees are particular good for this. If you happen to be using Blender and the Chicken exporter, it can do this for you.) Panda3d’s own scenegraph can be used to represent this hierarchy, and its built-in collision system will automatically take advantage of it, so out of the box you already have the tools necessary to implement such a system.

But Panda3d won’t split up your geometry into smaller chunks automagically. That must be done on your end. :slight_smile:

PS: A Panda-based Chaos Engine style game? Nice! Definitely would like to see that.

see the octree thread as to how to divide up the geometry for collision in an efficient manner…it is one of the best ways to collide with large terrains.

Thanks for the super quick responses guys!

Ah, this clears it up

I thought it was saying that collision rays were inefficient, I thought that was a bit odd.

Thanks Hypnos, I will try that code out when I get back from work (Its just mean that they stop me working on my game for a whole 9 hours a day isnt it? :stuck_out_tongue: )

Hi again folks

I have been struggling with these collisions, and I think I must be missing something fundamental.

When I try to implement the method that Hypnos suggested, my character alyways sticks in the same spot. I think this is because of the last line in this bit of code (from roaming ralph), since the collisionPusher wont match those criteria.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

If I remove that line though, or try and make it only match to collisions with the ray, it seems to stop working, and I can just float wherever I like in my level.

I have been reading the manual, and trying to implement the CollisionHandlerFloor and CollisionHandlerPusher, cos they look like the answer to my problems.

I scrapped all the old collisions from Roaming Ralph, and instead I have a traverser defined as follows

traverser = CollisionTraverser('mainTraverser')
base.cTrav = traverser

and then in the world class, I have the following (And there is an actor defined too, called mitch)

        #In theory this will handle wall collisions
        self.wallObject = self.mitch.attachNewNode(CollisionNode('wallNode'))
        self.wallObject.node().addSolid(CollisionSphere(0, 0, 1, 2))
        self.wallObject.show()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.wallObject,self.mitch)          
        base.cTrav.addCollider(self.wallObject,self.pusher)
        
        #and this should handle floor collisions
        self.floorObject = self.mitch.attachNewNode(CollisionNode('floorNode'))
        self.floorObject.node().addSolid(CollisionRay(0, 0, 0, 0, 0, -1))
        self.lifter = CollisionHandlerFloor()
        self.lifter.addCollider(self.floorObject,self.mitch)
        base.cTrav.addCollider(self.floorObject,self.lifter)

I guess, part of the problem is that the terrain is now not mentioned anywhere, so how would the CollisionHandlerPusher and CollisionHandlerFloor know about it. It needs to be somehow defined as an “into” object, am I right?

You don’t need to explicitly define objects that will be considered as Into objects during the collision traverse; Anything that is parented to the same node that is given to the traverser will automatically become an in object if it has any collision solids attached to it. Since you’re using the base.cTrav, it will automatically traverse the base render node every frame.

You do, however, need to make sure that the collision bitmasks are set appropriately. I believe, by default, every bit is set on for the Into mask but I could be wrong.

I’m not familiar with CollisionFloorHandler. I use CollisionGravityHandler myself, which as far as I can tell is a subset of CollisionFloorHandler that instead of automatically setting a Z-height, it will use a simple gravity/mass calculation to allow the object to fall a bit more realistically.

If you would like to see these concepts in action with working code, check out the GravityWalker class and example code which has been posted on the forums here before. This pretty much has all of the components you need right in one small Python class; Avatar control, a CollisionGravityHandler to keep the avatar out of the floor, and a wall CollisionPusherHandler sphere to keep it out of walls.

Update: Slight correction – Even if your mesh doesn’t have solids attached, it will still be considered an Into object as long as it’s given the proper masks.

Woohoo! I finally have a little guy that walks around and doesnt (often) fall through floors! :smiley:

Thanks for you help so far. I’m sure I will have more questions and comments, but I just thought I should let you know that your various advice helped me out a lot!