Hi, I’ve started to learn Panda 3D scripting but I have 2 annoying problems. First of all loading models, if I try to load a model with a simple function like this:
nothing works, I have the Panda window that opens but nothing’s inside. Why?
Second problem is about the Picker Class, if I try to use it I have an error at the compilation that says:
TypeError: CollisionTraverser::add_collider() argument 1 must be NodePath, not CollisionNode.
The class Picker is available on the website so I don’t understand why it gives me errors.
I tried but it didn’t work…it’s like the model is not there. Besides with the first method I’ve posted all works great…why all chenge if I encapsulate my method in a class?
That will disable the default mouse drive, not the mouse itself, and change the camera HPR to aim at your model.
Try if that works. If it does, it means your mouse drive moves the camera so that your model is completely out of sight. It can be difficult to navigate through empty space using the default mouse drive.
import direct.directbase.DirectStart
from pandac.PandaModules import*
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import*
from direct.task import Task
import math
import sys
import random
class World(DirectObject):
def _init_(self):
#load models
loadModels()
#end init
def loadModels():
#load T Rex
trex = loader.loadModel('/c/Documents and Settings/Robin/My Documents/Panda 3D/project01/models/t-rex/trex')
trex.reparentTo(render)
#end loadModels
#end Class World
base.useDrive()
world = World()
run()
I tried the lookAt(trex) but it didn’t work.
I use the latest Panda 3D version and I don’t use a debugger, only the Direct Session tool (by the way is there any tutorial about the Direct Session panel?).
OK, several Python scripting problems. You misspelled “[color=indigo]init” . There must be two underscores before and after. If it isn’t spelled exactly this way it is just another method and won’t be automatically called at instantiation.
If you want “[color=indigo]loadModels” to be an instance method you must define it as
def loadModels(self):
as all instance methods must have [color=blue]self as the first argument. To invoke the instance method from within the class use “self.loadModels()” not just “loadModels()”.
If, on the other hand you want “[color=indigo]loadModels” to be a static method, your current definition is fine, but to you need the line
loadModels=staticmethod(loadModels)
after the definition to make it explicitly static. To invoke the static method from within the class use “World.loadModels()” not just “loadModels()”.
I didn’t even know there was a direct session panel until you brought it up. It seems to be completely undocumented. If anyone knows about a tutorial, I would be interested as well.
You should consider using an IDE. It makes debugging much easier. There are many available for free. I use SPE.
You don’t seem to know Python very well, since you can’t make a proper class. That’s OK. It’s easy to learn.
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import*
from direct.task import Task
import math
import sys
import random
from Picker import Picker
class World(DirectObject):
# constructor
def __init__(self):
base.disableMouse()
camera.setPosHpr(Vec3(0,-15,7),Vec3(0,-15,0))
self.loadModels()
self.setupLighting()
#setup targets
self.setupCollisions()
# setup key controls
self.accept("escape",sys.exit)
self.accept("arrow_up", self.walk)
self.accept("arrow_left", self.turn,[-1])
self.accept("arrow_right", self.turn,[1])
#setup picking
self.picker = Picker()
self.panda.setTag("event", "hit-panda")
self.accept("mouse1", self.pick)
self.accept("hit-panda", self.hitPanda)
#start camera task
taskMgr.add(self.cameraFollowTask, 'cameraFollowTask')
# end __init__
def cameraFollowTask(self,task):
camera.lookAt(self.panda,Point3(0,0,4))
return Task.cont
#end cameraFollowtask
def loadModels(self):
# load a model
self.panda = Actor("/c/Panda3D-1.2.3/models/tutorialModels/panda-model",{"walk":"/c/Panda3D-1.2.3/models/tutorialModels/panda-walk4", "eat":"/c/Panda3D-1.2.3/models/tutorialModels/panda-eat"})
self.panda.reparentTo(render)
self.panda.setScale(.005)
self.panda.setH(180)
#load an environment
self.environ = loader.loadModel("/c/Panda3D-1.2.3/models/tutorialModels/Environment")
self.environ.reparentTo(render)
self.environ.setScale(0.25,0.25,0.25)
self.environ.setPos(-8,42,0)
#load targets
self.targets = []
for i in range(5):
target = loader.loadModel("/c/Panda3D-1.2.3/models/tutorialModels/Bambooshoot")
target.setScale(.1)
target.setPos(Vec3(random.uniform(-20,20),random.uniform(-15,15),0))
target.reparentTo(render)
self.targets.append(target)
# end loadModels
def setupCollisions(self):
#use an event collision handler (sends events on collisions)
self.cHandler = CollisionHandlerEvent()
#set the pattern for the event sent on collision
#"enter" plus the name of the object collided into
self.cHandler.setInPattern("ate-%in")
#make a traverser and make it the default traverser
self.cTrav = CollisionTraverser()
base.cTrav = self.cTrav
#add a sphere aroun the manda to be collide with bamboo
#get the bounding sphere of the panda
bounds = self.panda.getChild(0).getBounds()
center = bounds.getCenter()
radius = bounds.getRadius()
cSphere = CollisionSphere(center, radius)
cNode = CollisionNode("Panda")
cNode.addSolid(cSphere)
cNode.setIntoCollideMask(BitMask32.allOff())
cNodePath = self.panda.attachNewNode(cNode)
#enable this next line if you want to see the area that the collision sphere covers
cNodePath.show()
#add the Panda's collision node to the traverser as a collider
#***---PROBLEM---***
self.cTrav.addCollider(cNode,self.cHandler)
#**********************************************
#add sphere around the bamboos to be collided into
for target in self.targets:
cSphere = CollisionSphere(Point3(0,0,15),15)
cNode = CollisionNode("bamboo")
cNode.addSolid(cSphere)
cNodePath = target.attachNewNode(cNode)
cNodePath.show()
#listen for collisions from the panda into the bamboo
self.accept("ate-bamboo", self.eat)
#end setupCollisions
def walk(self):
dist = 5.0
angle = self.panda.getH()*math.pi/180.0
dx= dist*math.sin(angle)
dy = dist*-math.cos(angle)
pandaWalk = Parallel(
self.panda.posInterval(1.0,Vec3(self.panda.getX()+dx,self.panda.getY()+dy,0)),
self.panda.actorInterval("walk", loop=1,duration=1.0)
)
pandaWalk.start()
#end walk
def turn(self,dir):
pandaTurn = self.panda.hprInterval(.2,Vec3(self.panda.getH()-(10*dir),0,0))
pandaTurn.start()
#end turn
def eat(self, cEntry):
self.targets.remove(cEntry.getIntoNodePath().getParent())
cEntry.getIntoNodePath().getParent().remove()
pandaEar = self.panda.actorInterval("eat")
pandaEat.start()
#end eat
def setupLighting(self):
# start with a blank light attribute
lightAttribute = LightAttrib.makeAllOff()
# some directional light
dirLight = DirectionalLight('dirLight')
dirLight.setColor(Vec4(0.6,0.6,0.6,1.0))
dirLightNP = render.attachNewNode(dirLight.upcastToPandaNode()) # crashes without upcast
dirLightNP.setPos(Vec3(0.0,-10.0,10.0))
dirLightNP.setHpr(Vec3(0.0,-26.0,0.0))
lightAttribute = lightAttribute.addLight(dirLight) # add to attribute
# add a little extra ambient lighting just because
ambientLight = AmbientLight('ambientLight')
ambientLight.setColor(Vec4(0.25,0.25,0.25,1.0))
ambientLightNP = render.attachNewNode(ambientLight.upcastToPandaNode())
lightAttribute = lightAttribute.addLight(ambientLight)
# apply to world
render.node().setAttrib(lightAttribute)
# end setupLighting
def pick(self):
cEntry = self.picker.pick()
if (cEntry):
event = cEntry.gotIntoNodePath().getNetTag("event")
if (event):
messenger.send(event)
#end pick
def hitPanda(self):
print "OUCH! You hit the Panda."
currH = self.panda.getH()
pandaStunned = Sequence(
self.panda.hprInterval(.25,Vec3(currH-20,0,0)),
self.panda.hprInterval(.5,Vec3(currH+20,0,0)),
self.panda.hprInterval(.25,Vec3(currH,0,0))
)
pandaStunned.Start()
#end hitPanda
# end class World
world = World()
run()
by the way I have a problem at this line too:
self.cTrav.addCollider(cNode,self.cHandler)
it’s strange because I followed exactly the tutorial instructions.
The tut must be old. There was a little change since V1.1.0.
Pass the nodepath instead of the collision node :
self.cTrav.addCollider(cNodePath,self.cHandler)
ok, I have to learn these differences…unfortunately the tutorial is old and the problem persist in the class Picker. Picker is a module used to manage clicking on objects…some of you guys have the code of a Picker class that works? Thanks again for the help.
The two pages you used as a reference are very old, they apply to Panda versions prior to 1.1. (I think it was internal samples for students). It’s best to work with the tutorials shipped with current versions (they are up to date and well explained) or to use the online manual available from the website.
Anyway, solving errors in an old tutorials give you good debugging knowlegde