[SOLVED] The collision is detected, but not really detected.

I have three collision object, one BulletRigidBodyNode with BulletPlaneShape, one BulletCharacterControllerNode with BulletCapsuleShape and one BulletGhostNode with a lot of BulletBoxShape.

The BulletPlaneShape at (0,0,0); The BulletCharacterControllerNode on the BulletPlaneShape; BulletGhostNode over the BulletPlaneShape.

But BulletGhostNode and BulletPlaneShape of the collision has been detected always. When the BulletCharacterControllerNode close the BulletGhostNode, collision is detected.

It is a video:
http://www.tudou.com/programs/view/ANodHGxt0UE/

Here is my code:
http://ubuntuone.com/0gq3owAqoFB25IKw8xfhL9[color=darkred]bad
http://pan.baidu.com/share/link?shareid=107737&uk=3976327605[color=darkred]bad
http://noie.name/share/game20121103.7z

#!/usr/bin/python
#coding:utf8
#tropical.py

from direct.showbase.ShowBase import ShowBase
from panda3d.bullet import BulletWorld, BulletDebugNode, BulletPlaneShape, BulletRigidBodyNode
from panda3d.bullet import BulletSphereShape, BulletGhostNode, BulletBoxShape
from panda3d.core   import BitMask32
from pandac.PandaModules import Vec3
from pandac.PandaModules import LODNode
from pandac.PandaModules import NodePath
from pandac.PandaModules import TransparencyAttrib, Point3
from pandac.PandaModules import TransformState
import random

class Tropical():
	"""载入一个非洲风格的场景,重点在生成草坪。"""
	aX = 0
	aY = -200
	aZ = 0
	aH = 3.14
	cP = 0
	cZ = 2
	uS = True
	path = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1],
[1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1],
[1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1],
[1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]

	def __init__(self):
		m = loader.loadModel("tropical")
		m.reparentTo(render)
		
		# 加入草丛
		shape = BulletBoxShape(Vec3(4,4,0.5))
		self.ghost = BulletGhostNode('Ghost')
		for i in range(0,50):
			y = 220 - i*8 + random.uniform(-0.4,0.4)
			for j in range(0,40):
				if self.path[i][j]:
					x = j*8 - 150 + random.uniform(-0.4,0.4)
					# 使用LOD
					lod = LODNode('grass LOD node')
					lod_np = NodePath(lod)
					lod_np.reparentTo(render)
					g = loader.loadModel("grass1")
					g.reparentTo(lod_np)
					lod.addSwitch(40,5)
					
					g = loader.loadModel("grass2")
					g.reparentTo(lod_np)
					lod.addSwitch(50,40)
					
					g = loader.loadModel("grass3")
					g.reparentTo(lod_np)
					lod.addSwitch(200,50)
					lod_np.setPos(x,y,0)
					#lod_np.analyze()
				else:
					self.ghost.addShape(shape, TransformState.makePos (Point3(j*8 - 150,y,0)))
		ghostNP = render.attachNewNode(self.ghost)
		ghostNP.setZ(2) ### it over Shape.
		ghostNP.setCollideMask(BitMask32(0x0f))
		base.world.attachGhost(self.ghost)
		render.analyze()
		
		shape = BulletPlaneShape(Vec3(0,0,1), 0)
		stage = BulletRigidBodyNode('stageBase')
		stage.addShape(shape)
		base.world.attachRigidBody(stage)

When self.path[i][j]==1 to add a gress, self.path[i][j]==0 to add a shape in ghost.

By the way, I use panda3d1.9_1.9.0+cvs20121030~precise137_amd64.deb .

My guess is that you are talking about the output generated by these lines of code:

		print "getNumOverlappingNodes: ",
		print self.map.ghost.getNumOverlappingNodes()
		for node in self.map.ghost.getOverlappingNodes():
			print node
		return task.cont

I know that Bullet is a bit misleading here. What you do is not collision detection. The ghost object won’t ever collide with anything, since it’s collison bitmask ist set to 0x0 (all bits off!).

What you do is checking for which objects overlap with the ghost node. Overlap is - when talking about Bullet - overlap of BOUNDING BOXES.

The plane is infinite, so it’s bounding box is infinite too. This means no matter where you are you get an overlap between ghost and plane.

The character has a finite bounding box, roughtly the size of the capsule. The ghost object is composed of dozens of box shapes, giving it a total bounding volume of, well, roughly the size of your level. As far as the character is “outside” the level there won’t be an overlap. But everywhere “in between” the boxes which compose the ghost object there will be an overlap detected.

What is the effect you want to create? Maybe I can give advice on how to achieve what you want to do.

It turned out BOUNDING BOXES. I want to avatar use the usual speed, when it run on the ground. When avatar in the grass cluster, it use slow speed.

Maybe I should use python code directly.

You could use the methode BulletBodyNode.checkCollisionWith(PandaNode), i. e. ghostnode.checkWollisionWith(characterNode).

But in your case I think using a ghost node is an overkill. It might be easier to compute the “cell” coordinates (i,j) of the character each frame (e. g. Python’s divmod function), then lookup a speed adjusment factor from a dictionary with [i,j] key, and adjust the speed.

	path = [
[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,6,2,2,2],
[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,6,2,2,2],
[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,6,2,2,2],

			...
			...

[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,6,6,2,2,2,2,2,2,2,2,2,2],
[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,6,6,2,2,2,2,2,2,2,2,2,2],
[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,6,6,2,2,2,2,2,2,2,2,2,2]]

	def __init__(self):
		m = loader.loadModel("tropical")
		m.reparentTo(render)
		for i in range(0,50):
			y = 250 - i*10
			for j in range(0,30):
				x = j*10 - 150
				if self.path[i][j]==2:
					lod = LODNode('grass LOD node')

			...
			...

	def updateSpeed(self, task):
		x = int((self.playerNP.getX()+5+150)//10)
		y = int((250-self.playerNP.getY()+5)//10)
		if x>=0 and x<30 and y>=0 and y<50:
			self.playerNode.setLinearMovement((0,-self.map.path[y][x],0),True)
		else:
			self.playerNode.setLinearMovement((0,-0.5,0),True)
			print x,y
		return task.cont

It very good use. Thank you!