Panda Bullet

Hi, I was wondering, are Character Controller Nodes supported on heightfields?

I ask because I tried to place the character demo into the height field demo, with the code looking like:

import sys
import direct.directbase.DirectStart


from direct.actor.Actor import Actor
from direct.showbase.DirectObject import DirectObject
from direct.showbase.InputStateGlobal import inputState


from panda3d.core import AmbientLight
from panda3d.core import DirectionalLight
from panda3d.core import Vec3
from panda3d.core import Vec4
from panda3d.core import Point3
from panda3d.core import TransformState
from panda3d.core import BitMask32
from panda3d.core import Filename
from panda3d.core import PNMImage


from libpandabullet import BulletManager
from libpandabullet import BulletPlaneShape
from libpandabullet import BulletBoxShape
from libpandabullet import BulletRigidBodyNode
from libpandabullet import BulletDebugNode
from libpandabullet import BulletCapsuleShape
from libpandabullet import BulletCharacterControllerNode
from libpandabullet import BulletTriangleMesh
from libpandabullet import BulletTriangleMeshShape
from libpandabullet import BulletHeightfieldShape
from libpandabullet import ZUp


class World(DirectObject):
  def __init__(self):
    base.setBackgroundColor(0.0, 0.0, 0.6, 1)
    base.setFrameRateMeter(True)


    base.cam.setPos(0, -20, 4)
    base.cam.lookAt(0, 0, 0)


    # Light
    alight = AmbientLight('ambientLight')
    alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
    alightNP = render.attachNewNode(alight)


    dlight = DirectionalLight('directionalLight')
    dlight.setDirection(Vec3(1, 1, -1))
    dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))

    dlightNP = render.attachNewNode(dlight)


    render.clearLight()
    render.setLight(alightNP)
    render.setLight(dlightNP)


    # Input
    self.accept('escape', self.doExit)
    self.accept('r', self.doReset)
    self.accept('f1', self.toggleWireframe)
    self.accept('f2', self.toggleTexture)
    self.accept('f3', self.toggleDebug)
    self.accept('f5', self.doScreenshot)

    self.accept('space', self.doJump)
    self.accept('c', self.doCrouch)


    inputState.watchWithModifiers('forward', 'w')
    inputState.watchWithModifiers('left', 'a')
    inputState.watchWithModifiers('reverse', 's')
    inputState.watchWithModifiers('right', 'd')
    inputState.watchWithModifiers('turnLeft', 'q')
    inputState.watchWithModifiers('turnRight', 'e')


    # Task
    taskMgr.add(self.update, 'updateWorld')


    # Physics
    self.setup()


  # _____HANDLER_____


  def doExit(self):
    self.cleanup()
    sys.exit(1)


  def doReset(self):
    self.cleanup()
    self.setup()


  def toggleWireframe(self):
    base.toggleWireframe()


  def toggleTexture(self):
    base.toggleTexture()


  def toggleDebug(self):
    if self.debugNP.isHidden():
      self.debugNP.show()
    else:
      self.debugNP.hide()


  def doScreenshot(self):
    base.screenshot('Bullet')

  def doJump(self):
    self.player.setMaxJumpHeight(5.0)
    self.player.setJumpSpeed(8.0)
    self.player.doJump()


  def doCrouch(self):
    self.crouching = not self.crouching
    sz = self.crouching and 0.6 or 1.0


    self.player.getShape().setLocalScale(Vec3(1, 1, sz))


    self.playerNP.setScale(Vec3(1, 1, sz) * 0.3048)
    self.playerNP.setPos(0, 0, -1 * sz)


  # ____TASK___


  def processInput(self, dt):
    speed = Vec3(0, 0, 0)
    omega = 0.0


    if inputState.isSet('forward'): speed.setY( 3.0)
    if inputState.isSet('reverse'): speed.setY(-3.0)
    if inputState.isSet('left'):    speed.setX(-3.0)
    if inputState.isSet('right'):   speed.setX( 3.0)
    if inputState.isSet('turnLeft'):  omega =  120.0
    if inputState.isSet('turnRight'): omega = -120.0


    self.player.setAngularVelocity(omega)
    self.player.setLinearVelocity(speed, True)


  def update(self, task):
    dt = globalClock.getDt()


    self.processInput(dt)
    self.mgr.doPhysics(dt, 10, 0.008)


    return task.cont


  def cleanup(self):
    self.mgr = None
    self.worldNP.removeNode()


  def setup(self):
	self.worldNP = render.attachNewNode('World')


	# Manager
	self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
	self.debugNP.show()


	self.mgr = BulletManager()
	self.mgr.setGravity(Vec3(0, 0, -9.81))
	self.mgr.setDebugNode(self.debugNP.node())


	# Box (dynamic)
	shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))


	np = self.worldNP.attachNewNode(BulletRigidBodyNode('Box'))
	np.node().setMass(1.0)
	np.node().attachShape(shape)
	np.setPos(0, 0, 4)
	np.setCollideMask(BitMask32.allOn())


	self.mgr.attachRigidBody(np.node())


	self.boxNP = np # For applying force & torque
	#- This heightfield code with a character is broken.. why?
	img = PNMImage(Filename('models/elevation2.png'))
	shape = BulletHeightfieldShape(img, 3.0, ZUp)
	np = self.worldNP.attachNewNode(BulletRigidBodyNode('Heightfield'))
	np.node().attachShape(shape)
	np.setPos(0, 0, 0)
	np.setCollideMask(BitMask32.allOn())
	self.mgr.attachRigidBody(np.node())
	#- Comment out the code below for static planes and enable this code to see what I mean
	''' Heightfield is broken with character?
	#- Using static planes works fine with the character
	shape = BulletPlaneShape(Vec3(0, 0, 1), 0)
	np = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground'))
	np.node().attachShape(shape)
	np.setPos(0, 0, -1)
	np.setCollideMask(BitMask32.allOn())
	self.mgr.attachRigidBody(np.node())
	#- Comment the static plane code out and uncomment the heightfield code
	#- It then crashes saying:
	#- Assertion failed: (_flags & F_lock_count) != 0 at line 68 of c:\buildslave\dev_sdk_win32\build\panda3d\built\include\mutexSimpleImpl.I
	'''
	# Character
	self.crouching = False


	h = 1.75
	w = 0.4
	shape = BulletCapsuleShape(w, h - 2 * w, ZUp)


	node = BulletCharacterControllerNode(shape, 0.4, 'Player')
	np = self.worldNP.attachNewNode(node)
	np.setPos(-2, 0, 4)
	np.setH(0)
	np.setCollideMask(BitMask32.allOn()


	self.mgr.attachCharacter(np.node())


	self.player = node # For player control


	self.playerNP = Actor('models/ralph/ralph.egg', {
			              'run' : 'models/ralph/ralph-run.egg',
			              'walk' : 'models/ralph/ralph-walk.egg',
			              'jump' : 'models/ralph/ralph-jump.egg'})
	self.playerNP.reparentTo(np)
	self.playerNP.setScale(0.3048) # 1ft = 0.3048m
	self.playerNP.setH(180)
	self.playerNP.setPos(0, 0, -1)


b = World()
run()

that, and it error’s out (crashes python.exe)
here’s the only thing it prints to the terminal:

Assertion failed: (_flags & F_lock_count) != 0 at line 68 of c:\buildslave\dev_sdk_win32\build\panda3d\built\include\mutexSimpleImpl.I

was just curious if I had done something wrong or what, I know this is still uber beta, even if it is uber cool.

~powerpup118