[RESOLVED] PhysicsCollisionsHandler

Ok, so I created a sample program to try and test my understanding of PhysicsCollisionHandler. I couldn’t even get this to work!

import direct.directbase.DirectStart
from pandac.PandaModules import PhysicsCollisionHandler
from pandac.PandaModules import ForceNode
from pandac.PandaModules import ActorNode, BitMask32
from pandac.PandaModules import CollisionNode
from pandac.PandaModules import CollisionTraverser
from pandac.PandaModules import CollisionSphere
from pandac.PandaModules import LinearVectorForce, CollisionTraverser
from direct.showbase.DirectObject import DirectObject

class World(DirectObject):

    def __init__(self):
        ralph = loader.loadModel("models/ralph")
        ralph.reparentTo(render)
        
        ralph.setZ(4.1) # acts really wierd
##        ralph.setZ(5.0) # intersects with the ground just fine
       
        wallModel = "box"
        wall = loader.loadModel(wallModel)
        wall.setPos(-50, -50, 0)
        wall.setScale(100, 100, 1)
        wall.reparentTo(render)
       
        base.particlesEnabled = True
        base.enableParticles()
       
        gravityFN=ForceNode('world-forces')
        gravityFNP=render.attachNewNode(gravityFN)
        gravityForce=LinearVectorForce(0,0,-9.81) 
        gravityFN.addForce(gravityForce)

        base.physicsMgr.addLinearForce(gravityForce)
       
        base.cTrav = CollisionTraverser()
        base.cTrav.setRespectPrevTransform(True)
           
        anp = render.attachNewNode(ActorNode("actor"))
        anp.setZ(50)
        anp.node().getPhysicsObject().setMass(35.0)
        fromObject = anp.attachNewNode(CollisionNode("agentCollisionNode"))
        fromObject.node().addSolid(CollisionSphere(0, 0, 0, 2.5))
        fromObject.node().setFromCollideMask(BitMask32.allOn())
        fromObject.node().setIntoCollideMask(BitMask32.allOff())
        fromObject.show()
       
        pusher = PhysicsCollisionHandler()
        pusher.setDynamicFrictionCoef(0.5)
        pusher.setStaticFrictionCoef(0.7)
        pusher.addCollider(fromObject, anp)
        base.cTrav.addCollider(fromObject, pusher)

        ralph.reparentTo(anp)
        base.physicsMgr.attachPhysicalNode(anp.node())

w = World()
run() 

Ralph isn’t even falling! Did I miss something?

EDIT: added the ralph.reparentTo(anp) line.
EDIT: added base.physicsMgr.attachPhysicalNode(anp.node()), and ralph.setZ(50)
EDIT: I changed to ralph.setZ(5.0) so I could see the collision solid and ralph at the same time. I also added anp.setZ(50) and fromObject.show()

Ralph is parented directly to render. Your anp might be falling, but that’s got nothing to do with Ralph. If you want Ralph to fall along with the anp, parent him to anp.

David

I just added the line:

ralph.reparentTo(anp)

To the end of my init function. It didn’t seem to make a difference. Ralph still just floats in the air.

You also forgot to call:

base.physicsMgr.attachPhysicalNode(anp.node())

Furthermore, your starting point is a little too low; you’re already below the floor.

David

First off, thanks for looking at this. Having a working example is worth volumes to me.

That got me a little further. Now he falls straight through the floor (which I confusingly decided to call wall :confused:). I’ve tried grabbing the CollisionNode from the wall model and setting the IntoCollisionMask to BitMask32.allOn(), but it doesn’t seem to have an effect. What else am I missing?

Like I said, your starting point is too low. You can see this visually if you call show() on your collision node. The sphere starts out in the middle of the floor.

Set the collision node, or anp itself, to a higher initial Z value, or set the floor to a lower initial Z value.

David

Sorry, I should have made a post for this. I’ve already edited the first post to add all the suggestions you made, including a ralph.setZ(50). That should be high enough. He still falls straight through.

Ralph is just the visible model. The center of collisions is your CollisionNode, fromObject. That’s parented to anp, which has no initial transform; and the collision sphere is still at (0, 0, 0). It’s hidden by default, but you can make it visible by calling fromObject.show().

David

Cool, I’m getting closer.

When I used CollisionHandlerPusher, I basically created a CollisionSphere that would surround ralph like a force field. Using that strategy hasn’t worked so far for the PhysicsCollisionHandler.

It seems that if ralph is in any way intersecting with the CollisionSphere they both disappear from view. Furthermore, when ralph is in the center of the sphere, he falls right through the floor.

The only way I was able to get a collision was with the above code. At z = 5.0 he’s barely hovering over the CollisionSphere. If I lower that number to 4.2, he and the sphere go all over the place. Try it and see what I mean.

Thanks for your help so far. Any ideas of what’s wrong now?

Sure. It’s this line:

fromObject.node().setFromCollideMask(BitMask32.allOn()) 

You are setting all bits on, which includes geom (visible geometry) bits. That means the sphere is colliding with Ralph himself! Of course, you need visible geometry in order to collide with your wall, so you could compensate for this by making ralph intangible (set all bits off for him).

David

drwr, you are the man!

from direct.directbase import DirectStart
from pandac.PandaModules import PhysicsCollisionHandler
from pandac.PandaModules import ForceNode
from pandac.PandaModules import ActorNode, BitMask32
from pandac.PandaModules import CardMaker
from pandac.PandaModules import CollisionNode
from pandac.PandaModules import CollisionTraverser
from pandac.PandaModules import CollisionSphere
from pandac.PandaModules import LinearVectorForce, CollisionTraverser
from direct.showbase.DirectObject import DirectObject

# Load a simple model
ralph = loader.loadModel("models/ralph")
ralph.reparentTo(render)

# This is needed so we don't calculate collisions on the actual model,
# but on the collision node we will add later
ralph.setCollideMask(BitMask32.allOff())

# Generate a flat surface we can land on
cm = CardMaker("ground")
cm.setFrame(-50, 50, -50, 50)
ground = render.attachNewNode(cm.generate())
ground.setPos(0, 0, 0)
ground.lookAt(0, 0, -1)
ground.reparentTo(render)

# Enables the built-in physics
base.enableParticles()

# Set up the gravity force
gravityFN=ForceNode('world-forces')
gravityFNP=render.attachNewNode(gravityFN)
gravityForce=LinearVectorForce(0,0,-9.81) 
gravityFN.addForce(gravityForce)

# Attach it to the global physics manager
base.physicsMgr.addLinearForce(gravityForce)

# Set up the global collision traverser
base.cTrav = CollisionTraverser()
# Uncomment this if any of your entities are moving fast
#base.cTrav.setRespectPrevTransform(True)
   
# Whenever we want to inter-act with anything to do with collisions/physics,
# we want to use the actor node path
anp = render.attachNewNode(ActorNode("actor"))
# sets it high enough so we can see it fall
anp.setZ(30)
# Sets up the mass. Note that in this scenario, mass is not taken into 
# consideration. 
anp.node().getPhysicsObject().setMass(35.0)
# the fromObject is our collision information. The documentation for Panda3d
# recommends that we use a sphere to handle collisions.
fromObject = anp.attachNewNode(CollisionNode("agentCollisionNode"))
# The sphere is 2.5 up from ralph's feet and 2.5 in radius.
fromObject.node().addSolid(CollisionSphere(0, 0, 2.5, 2.5))
# We want to handle any sort of collision that happens to us, but not 
# vice-versa
fromObject.node().setFromCollideMask(BitMask32.allOn())
fromObject.node().setIntoCollideMask(BitMask32.allOff())
# Uncomment this to show the collision shpere
#fromObject.show()

# Create a collision handler to handle all the physics
pusher = PhysicsCollisionHandler()
# attach our new collision node along with our actor node to it
pusher.addCollider(fromObject, anp)
# Add the handler to our global traverser
base.cTrav.addCollider(fromObject, pusher)

# Everywhere our physics 'bubble' goes, we want to stay inside it
ralph.reparentTo(anp)
# Tell the global physicsMgr about our actor node
base.physicsMgr.attachPhysicalNode(anp.node())

# Put the camera in a good position
base.disableMouse()
base.camera.setPos(0, -100, 10)
base.camera.lookAt(0, 0, 0)

# run the simulation
run() 

Huzzah! It finally works! Thank you for all your help, you’ve given me hope in adding physics to my project. I’ll find a better place to post this somewhere. I wouldn’t mind if it was added to the samples in the next release, considering the first thing I did was grep the samples for PhysicsCollisionHandler. Hopefully this helps other people.