I’m trying to take the “walking on uneven ground” sample http://www.panda3d.org/manual/index.php/Uneven_Terrain and make ralph walk to wherever is clicked.
It seemed simple enough, I’ve already managed to get “picking” working in another sample; but I can’t get it working here.
As I understand it, whenever I click I should get:
- one or more hits in the CollisionHandlerQueue
- see my collisionRay change direction whilst its origin stays fixed (at the cameras)
neither of these things appear to happen but I can’t figure out why. As a result I don’t get the right location when I click.
Can anyone help
Rich
# Author: Ryan Myers
# Models: Jeff Styers, Reagan Heller
# Last Updated: 6/13/2005
#
# This tutorial provides an example of creating a character
# and having it walk around on uneven terrain, as well
# as implementing a fully rotatable camera.
import direct.directbase.DirectStart
from pandac.PandaModules import CollisionTraverser,CollisionNode
from pandac.PandaModules import CollisionHandlerQueue,CollisionRay
from pandac.PandaModules import Filename
from pandac.PandaModules import PandaNode,NodePath,Camera,TextNode
from pandac.PandaModules import Vec3,Vec4,BitMask32, GeomNode
from direct.gui.OnscreenText import OnscreenText
from direct.actor.Actor import Actor
from direct.task.Task import Task
from direct.showbase.DirectObject import DirectObject
import random, sys, os, math
#for Pandai
from panda3d.ai import *
SPEED = 0.5
class World(DirectObject):
def __init__(self):
self.moving = False
base.win.setClearColor(Vec4(0,0,0,1))
base.cam.setPosHpr(17.79,-87.64,90.16,38.66,325.36,0)
# Set up the environment
#
# This environment model contains collision meshes. If you look
# in the egg file, you will see the following:
#
# <Collide> { Polyset keep descend }
#
# This tag causes the following mesh to be converted to a collision
# mesh -- a mesh which is optimized for collision, not rendering.
# It also keeps the original mesh, so there are now two copies ---
# one optimized for rendering, one for collisions.
self.environ = loader.loadModel("models/world")
self.environ.reparentTo(render)
self.environ.setPos(12,0,0)
self.box = loader.loadModel("models/box")
self.box.reparentTo(render)
self.box.setPos(-29.83,0,0)
self.box.setScale(1)
self.box1 = loader.loadModel("models/box")
self.box1.reparentTo(render)
self.box1.setPos(-51.14,-17.90,0)
self.box1.setScale(1)
# Create the main character, Ralph
#ralphStartPos = self.environ.find("**/start_point").getPos()
ralphStartPos = Vec3(-98.64,-20.60,0)
self.ralph = Actor("models/ralph",
{"run":"models/ralph-run",
"walk":"models/ralph-walk"})
self.ralph.reparentTo(render)
self.ralph.setScale(1)
self.ralph.setPos(ralphStartPos)
ralphaiStartPos = Vec3(-50,20,0)
self.ralphai = Actor("models/ralph",
{"run":"models/ralph-run",
"walk":"models/ralph-walk"})
self.pointer = loader.loadModel("models/arrow")
self.pointer.setColor(1,0,0)
self.pointer.setPos(-7.5,-1.2,0)
self.pointer.setScale(3)
self.pointer.reparentTo(render)
# Game state variables
self.isMoving = False
# Set up the camera
base.disableMouse()
# We will detect the height of the terrain by creating a collision
# ray and casting it downward toward the terrain. One ray will
# start above ralph's head, and the other will start above the camera.
# A ray may hit the terrain, or it may hit a rock or a tree. If it
# hits the terrain, we can detect the height. If it hits anything
# else, we rule that the move is illegal.
self.cTrav = CollisionTraverser()
self.ralphGroundRay = CollisionRay()
self.ralphGroundRay.setOrigin(0,0,1000)
self.ralphGroundRay.setDirection(0,0,-1)
self.ralphGroundCol = CollisionNode('ralphRay')
self.ralphGroundCol.addSolid(self.ralphGroundRay)
self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
self.ralphGroundHandler = CollisionHandlerQueue()
#self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)
self.camGroundRay = CollisionRay()
self.camGroundCol = CollisionNode('camRay')
self.camGroundCol.addSolid(self.camGroundRay)
#self.camGroundCol.setFromCollideMask(GeomNode.getDefaultCollideMask())
self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
self.camGroundHandler = CollisionHandlerQueue()
self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)
# Uncomment this line to see the collision rays
#self.ralphGroundColNp.show()
self.camGroundColNp.show()
#Uncomment this line to show a visual representation of the
#collisions occuring
self.cTrav.showCollisions(render)
#self.setAI()
self.accept("mouse1", self.setMove)
def setMove(self):
if base.mouseWatcherNode.hasMouse():
mpos = base.mouseWatcherNode.getMouse()
self.camGroundRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
self.cTrav.traverse(render)
print "trav: %u" % (self.camGroundHandler.getNumEntries())
print self.camGroundRay.getOrigin()
print self.camGroundRay.getDirection()
if self.camGroundHandler.getNumEntries() > 1:
# This is so we get the closest object
self.camGroundHandler.sortEntries()
pickedObj = self.camGroundHandler.getEntry(1).getIntoNodePath()
print pickedObj.getPos()
if (not pickedObj.isEmpty() and
pickedObj.getName() == 'terrain'):
dest = self.camGroundHandler.getEntry(1).getSurfacePoint(render)
self.pointer.setPos(dest)
#self.AIbehaviors.pathFindTo(self.pointer)
#self.ralph.loop("run")
#self.moving = True
# Accepts arrow keys to move either the player or the menu cursor,
# Also deals with grid checking and collision detection
def move(self):
# Get the time elapsed since last frame. We need this
# for framerate-independent movement.
elapsed = globalClock.getDt()
startpos = self.ralph.getPos()
# Now check for collisions.
self.cTrav.traverse(render)
# Adjust ralph's Z coordinate. If ralph's ray hit terrain,
# update his Z. If it hit anything else, or didn't hit anything, put
# him back where he was last frame.
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)
self.ralph.setP(0)
return Task.cont
def setAI(self):
#Creating AI World
self.AIworld = AIWorld(render)
self.accept("space", self.setMove)
self.AIchar = AICharacter("ralph",self.ralph, 60, 0.05, 25)
self.AIworld.addAiChar(self.AIchar)
self.AIbehaviors = self.AIchar.getAiBehaviors()
self.AIbehaviors.initPathFind("models/navmesh.csv")
self.AIbehaviors.addStaticObstacle(self.box)
self.AIbehaviors.addStaticObstacle(self.box1)
#AI World update
taskMgr.add(self.AIUpdate,"AIUpdate")
#to update the AIWorld
def AIUpdate(self,task):
self.AIworld.update()
if self.moving:
if self.AIbehaviors.behaviorStatus("pathfollow") == "done":
self.ralph.stop()
self.ralph.pose("walk", 5)
self.moving = False
else:
self.move()
return Task.cont
w = World()
run()