Collision in complex scenes : the great challenge !!!

To divide correctly my project, I made a class for main character and another class to manage the scene.

So, using as referece the roaming ralph sample, I saw the technique to create collisions between character and terrain for example, but like I made two classe, what I need to share between objects ?

For example, I’ll need share the CollisionHandler made in each class ?

It doesn’t matter so much about CollisionHandlers, you just need to share a CollisionTraverser between Panda objects that will collide. If they aren’t added together in the same Traverser, then they can’t ever possibly collide together.

If you want simple, you can create a CollisionTraverser and then assign it to base.cTrav. From there, Panda will take care of handling collisions in its game loop. It will call traverse per-frame and automatically reset the fluid positions.

CollisionHandlers can be assigned per object, per class, per whatever. If you want simplicity, define a single CollisionHandler and then just pass it around to all of your classes. Or you can use a CollisionHandler per class – It’s really up to what you want, and how you want to handle collisions.

Even having just one CollisionTraverser isn’t necessary. You can set up a CollisionTraverser any time, and have it collide whenever you want.

This is a common misconception, but it isn’t actually true. Remember, an “into” object doesn’t even have to be added to the Traverser at all; you only add “from” objects to the Traverser. When two objects collide, one of them is a “from” object and the other one is an “into” object; it doesn’t matter for the purposes of the collision whether the “into” object is added to a Traverser or not.

So, the only thing that really matters is that both objects are added to the same scene graph, e.g. both of them are somewhere under render. You can add either or both of them to the CollisionTraverser of your choice.

David

Oops, poor choice of my words. I was speaking from a purely From-centric viewpoint, ie: Two From objects in separate traversers would never generate contact points against each other.

To iterate, basically anything that has a CollisionSolid assigned to it will be considered as an Into object during a collision pass, by any CollisionTraverser that exists. (As long as, like David said, they are in the same scene graph.)

Now that I fix the problems about camera…come back again to collisions.
So…

Chicken has a little tutorial explaining the use of tags for objects (meshes I believe) to turn “on” the collision (The topic is
Exporting ObjectType flags or Tags for your objects: in documentation).

Based on Ralph Roaming sample I did it (this class represent my player):

        self.BillyCollisionTraverser = CollisionTraverser()
        self.BillyCollisionRay = CollisionRay()
        self.BillyCollisionRay.setOrigin(0,0,1000)
        self.BillyCollisionRay.setDirection(0,0,-1)
        self.BillyCollisionNode = CollisionNode("billy")
        self.BillyCollisionNode.addSolid(self.BillyCollisionRay)
        self.BillyCollisionNode.setFromCollideMask(BitMask32.bit(0))
        self.BillyCollisionNode.setIntoCollideMask(BitMask32.allOff())
        self.BillyCollisionNodeNp = self.model.attachNewNode(self.BillyCollisionNode)
        self.BillyCollisionHandler = CollisionHandlerQueue()
        self.BillyCollisionTraverser.addCollider(self.BillyCollisionNodeNp, self.BillyCollisionHandler)

And in moving function:

...
        entries = []
        for i in range(self.BillyCollisionHandler.getNumEntries()):
            entry = self.BillyCollisionHandler.getEntry(i)
            print entry.getName()
            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() == "gramado"):
            self.model.setZ(entries[0].getSurfacePoint(render).getZ())

Here a piece of my level at current state, I give a specific name, but I guess I dont give a collision for the object (in actor for this mesh for example I dont put anything).


By mcunha98

Where is the error ?

Hi people…

I’m trying…belive me :blush:

Based on tutorial by Paulo Barbeiro, I did some piece of the entire code for the collision, but I believe doesn’t work because I dont put a handler/create collision relative to scene.

Please again I ask your help to understand.

This piece of code is relative to class of player:

        
        base.cTrav = CollisionTraverser()
        base.pusher = CollisionHandlerPusher()
        base.floor = CollisionHandlerFloor()
        base.floor.setMaxVelocity(1)
                        
        self.BillyCollisionRay = CollisionRay(0,0,-1,0,0,-1)
        self.BillyCollisionNode = CollisionNode("BillyRay")
        self.BillyCollisionNode.addSolid(self.BillyCollisionRay)
        self.BillyCollisionNodeNP = self.model.attachNewNode(self.BillyCollisionNode)
        self.BillyCollisionNodeNP.show()
        
        base.cTrav.addCollider(self.BillyCollisionNodeNP,base.floor)

Here you see the ray starting from player to down…

By mcunha98

Now the problem…here the piece of code to make (construir) the scene objeto, here the level is loaded and here I believe is need a manipulation from all objects in scene, correct ?

	def construir(self):
		self.worldspawn = None

		if self.model_filename == None:
			print "Cenario nao teve arquivo de parametro informado !"
			return
		
		if self.billy == None:
			print "Billy nao foi passado para o cenario !"
			return
		
		arquivo = "level/" + self.model_filename + "/@map.egg"
		print "Iniciando carregamento de " + arquivo
		self.model = loader.loadModel(arquivo)
		objetos = self.model.findAllMatches("**")
		
		self.worldspawn = self.model.findAllMatches("**/worldspawn") 
		if self.worldspawn != None and self.worldspawn.isEmpty() == False:
			self.worldspawn = self.worldspawn.getPath(0)
			print "Worldspawn encontrado e Billy posicionado !"
		
		self.ambientLight = render.attachNewNode( AmbientLight( "ambientLight" ) )
		self.ambientLight.node().setColor( Vec4( .1, .1, .1, 1 ) )

		#custom collisions and triggers ?!?!
		for objeto in objetos:
			objeto_node = objeto.node()
			print "Depurando " + objeto_node.getName() + " do tipo " + str(objeto_node.getType()) + " e classe " +  str(objeto_node.getClassType())
			
			if objeto_node.getName() == "cam-pos-001":
				#base.camera.setPos(objeto_node.getPos())
				print "Campos001 encontrado !"
		
		print "Finalizando carregamento de " + arquivo
		self.model.reparentTo(render)

Now the collisions works, but not 100%
I based my application in sphere , but pieces (like legs) of character dont create collision with scene.

See the image, what I need to do ?

        base.cTrav = CollisionTraverser()
        base.pusher = CollisionHandlerPusher()
        base.floor = CollisionHandlerFloor()
        base.floor.setMaxVelocity(5)
                        
        self.BillyCollisionNodeEsfera = CollisionNode("BillyEsfera")
        self.BillyCollisionNodeEsfera.addSolid(CollisionSphere(0,0,0,3))
        self.BillyCollisionNodeEsferaNP = self.model.attachNewNode(self.BillyCollisionNodeEsfera)
        self.BillyCollisionNodeEsferaNP.show()
        base.cTrav.addCollider(self.BillyCollisionNodeEsferaNP,base.pusher)
        base.pusher.addCollider(self.BillyCollisionNodeEsferaNP,self.model)
        
        self.BillyCollisionNodeRaio = CollisionNode("BillyRaio")
        self.BillyCollisionNodeRaio.addSolid(CollisionRay(0,0,-5,0,0,-1))
        self.BillyCollisionNodeRaioNP = self.model.attachNewNode(self.BillyCollisionNodeRaio)
        self.BillyCollisionNodeRaioNP.show()
        base.cTrav.addCollider(self.BillyCollisionNodeRaioNP,base.floor)
        base.floor.addCollider(self.BillyCollisionNodeRaioNP,self.model)

put your ‘self.BillyCollisionNodeRaio’ a bit down to his feet or use a sphere like pusher at his feet, I think CollisionRay is the right choice.

EDIT:
this line you have to edit:
self.BillyCollisionNodeRaio.addSolid(CollisionRay(0,0,-5,0,0,-1))

I did before you tell … :laughing: :blush: :cry:

edit: I put the ray exactly on his feets…

By mcunha98

Guys , help please !?!
:blush:

i’d sugest you create a nodepath for the player, and have the model as child to this nodepath, also attach the collision detection to this first nodepath. this way you can place the model at any height.

(not sure if this was really your question)

Actually I prefer explain again the problem before of change my code once again.

I get the collisions for the object Sphere correctly and the ray used to make the pusher action works fine too. But the problem is this…the collision works for the sphere and not for the model.

For example, the legs and the head of model enter in another objects (like houses ), there is a collision, but it work for the sphere and not for the model.

Do you believe, if I change the technique using a nodepath, will work how I want ?

I believe the sphere is the shape of your model, you have to use the appropriated solid for your model or put many solids as you wish, for instance, put solids for the head and legs.

:confused: :open_mouth: :blush:

I’ll complicate something simple.
Your idea is put a solid for hands, head, legs, etcc ???
Imagine the management of this objects for collision…

There are more easy ways…I believe…right ? :unamused:

yeah if the head of your model enters in another objects is because it does not have collision solid. You’ll have to attach one to the head.

you said your collision solids are working but the model, so the sphere represents your model, the sphere is your model. Try to scale the sphere a bit more before adding another solid.

if i understand you correctly, the problem is that your model intersects with other geometry, even tough you have defined a collisionpusher?

how about using a different collision solid, or make the sphere larger? for example take a collisionTube instead of the collisionSphere?

I changed the solid used for the collision for a tube, but the tube dont cause collisions :blush:

See the steps…

By mcunha98

Maybe the sphere work better, I’ll change the dimensions of sphere that way I put entire model in internal area and I’ll post the result…

From what I’ve seen, I think there’s something wrong in how you set up your scene.
First, make sure collisions are active on all your level meshes.
I suspect of this, since in some screens collisions were working, in others the same set up was screwed!
In the egg file there must be the {Polyset keep descend} tag,
or better if you used the octree script in chicken exporter, all the models will have a {Barrier} counterpart, invisible and optimized for collisions.
After this, try to adapt this little piece of code I took from my project:
self.model is the player’s actor.

    def setUpCollision(self):
        #sets up the collision solids and the Handlers
        base.cTrav=CollisionTraverser("cTrav")

        #staying on the ground using a vertical ray and a collisionHandlerFloor
        self.floorRay=self.model.attachCollisionRay("", 0, 0, 3, 0, 0, -1, 
                                                    BitMask32.bit(1), BitMask32.allOff())
        #this is the cHadler that will make use of the floorRay
        self.floorHandler=CollisionHandlerGravity()
        self.floorHandler.setGravity(98)#magic number here
        self.floorHandler.addCollider(self.floorRay, self.model)
        
        base.cTrav.addCollider(self.floorRay, self.floorHandler)
        #self.floorRay.show()#uncomment to see ray

        #this sphere keeps the model from walking through walls
        self.wallSphere1=self.model.attachCollisionSphere("", 0, 0, 2, 1.6, 
                                                          BitMask32.bit(1), 
                                                          BitMask32.allOff())
        #height from self.model=2|radius=1.6
        #self.wallSphere1.show()#uncomment to see sphere
        
        #this is the handler that will check for collisions with walls
        self.pusherHandler=CollisionHandlerPusher()
        self.pusherHandler.addCollider(self.wallSphere1, self.model)
        
        base.cTrav.addCollider(self.wallSphere1, self.pusherHandler)

In your code you weren’t setting CollisionBitMasks, maybe the ray was trying to collide against your other solid giving strange behaviour.

Anyway, the ray must really start from above the point it has to put on the ground, doesn’t it?

Ausir

Thanks for share your piece of code, I try using it but dont work too…

Here you see the setup in chicken, really correct …

By mcunha98 at 2009-08-15

But here the result:

By mcunha98 at 2009-08-15

I did a vbscript to put the tag in my egg every time it found a tag, so all objects has a collide tag.

Your code seems like my code, so, I change my code for your suggestion, but dont work yet…

self.floorRay=self.model.attachCollisionRay("",0,0,-7.5,0,0,-1,BitMask32.bit(1), BitMask32.allOff())
        self.floorHandler = CollisionHandlerGravity()
        self.floorHandler.setGravity(30)
        self.floorHandler.addCollider(self.floorRay, self.model)
        base.cTrav.addCollider(self.floorRay, self.floorHandler)
        self.floorRay.show()
        self.wallSphere1=self.model.attachCollisionSphere("",0,0,0,7.2,BitMask32.bit(1),BitMask32.allOff())
        self.wallSphere1.show()
        self.pusherHandler=CollisionHandlerPusher()
        self.pusherHandler.addCollider(self.wallSphere1, self.model)
        base.cTrav.addCollider(self.wallSphere1, self.pusherHandler)

Here a sample of a group in egg:

<Group> props-pa_props-pa_pro {
  <Collide>{Polyset keep descend}

What is wrong ??? :blush: :cry:

Please…see this video:

youtube.com/watch?v=CgOHOB7sHXk

I record a video where is possible see the odd behaviour off collisions, the model slice in some areas and in another areas it are blocked…

:blush: :cry: