So I’ve been making some progress, and after starting something new from scratch, inspired mostly by astelix’s tutorials and the Roaming Ralph sample program, I’ve managed to get a simple environment where my actor runs around on keyboard commands, climbs slopes, and does not walk through walls.
The actor uses a collision sphere to keep from going through walls, and a collision ray to detect terrain height, apparently - you see, I didn’t actually intend for it to detect terrain height, but suddenly it was doing it, even though there was nothing analoguous to Roaming Ralph’s height detection, so I’ve left the code as is for fear of breaking it.
However, I am having a hard time implementing physics, because when I do so, the actor seems to fall directly through the world and disappear, even though there is a CollisionHandlerFloor() and such. This is when I have implemented gravity and enabled physics on the actor’s appropriate node. I have uploaded the file, including the environment in .blend and .egg, as well as two versions of the code, one with physics (in the third, fourth and fifth “sections” of the World class) and one without. The actor used is the smiley model that comes with Panda. I would be very grateful if someone could take a look at the code and tell me what’s wrong with my physics.
easy-share.com/1911301637/Zip_SSTE.rar
Also, I have a minor question. How do I use the addImpulse() function? Is there a clearly commented, simple, stand-alone snippet of code I could take a look at? What do I have to use it on? I’ve tried using it on various actors and nodes and it never works, always returning an error like “has no attribute addImpulse”. And why does it always seem to appear next to a “getPhysicsObject”? (which also gets the “has no attribute” errors) I get the same errors when trying to use LerpInterval or PosInterval, too, so I must have systematically not understood something. I am trying to create a jump function, see.
EDIT: Oh, and a second small question: I have successfully implemented cartoon shading on an angular, blocky terrain - but it doesn’t make all the edges of the terrain black, only those not directly in front of the camera. How can I make it so that all the terrain’s edges are black?
Thanks for any help you can provide!
For those who would rather not download the file, here is the physics-related part of the code:
#Now let's try and enable a physics system. First, traversers and handlers.
self.cTrav = CollisionTraverser()
self.floorHandler = CollisionHandlerFloor()
self.floorHandler.setMaxVelocity(24)
self.wallHandler = CollisionHandlerPusher()
self.physicsHandler = PhysicsCollisionHandler()
#Now, we enable particles, in order to enable physics.
self.enableParticles()
#Then, gravity.
self.gravityFN = ForceNode("world-forces")
self.gravityFNP = render.attachNewNode(self.gravityFN)
self.gravityForce = LinearVectorForce(0,0,-9.81)
self.gravityFN.addForce(self.gravityForce)
#Add the gravity to the physics manager.
base.physicsMgr.addLinearForce(self.gravityForce)
#Now, we will need masks for the walls and floors.
self.wallMask = BitMask32.bit(1)
self.floorMask = BitMask32.bit(2)
#==========
#Now to start, we shall load the model, and call it "environ".
self.environ = self.loader.loadModel("StickSoldiersTestEnvironment")
self.environ.reparentTo(self.render)
#The model is quite small, so we need to make it much bigger.
self.environ.setScale(25)
#We can center the model at the origin.
self.environ.setPos(0, 0, 0)
#We also ought to set the camera position; remember, distances in
#Panda3D are in rather large numbers!
base.camera.setPos(0, -250, 160)
#If we are to implement physics, we must tell the game which
#parts of the map belong to which BitMask. First, turn off all general
#BitMasks.
self.environ.setCollideMask(BitMask32.allOff())
#Now we activate the indivitual colliders.
self.floorCollider = self.environ.find("**/floorcollider")
self.wallCollider = self.environ.find("**/wallcollider")
#And set their BitMasks.
#ERROR: This is apparently "empty".
self.floorCollider.node().setIntoCollideMask(self.floorMask)
self.wallCollider.node().setIntoCollideMask(self.wallMask)
#==========
#So we want to make an actor with physics enabled; let's give that a shot.
self.actorNP = NodePath(PandaNode("smiley-physics-node"))
self.actorNP.reparentTo(base.render)
self.actor = self.loader.loadModel("smiley")
self.actor.reparentTo(self.actorNP)
self.actorNode = ActorNode("smiley-physics")
self.actorNodePath = self.actorNP.attachNewNode(self.actorNode)
base.physicsMgr.attachPhysicalNode(self.actorNode)
self.actor.reparentTo(self.actorNodePath)
#Let's put the model a bit in the air, to make it visible.
self.actor.setPos(0, 0, 15)
self.actorNP.setPos(0,0,4)
#The model is also rather small, so let's enlarge it.
self.actor.setScale(4)
#Now let's handle the collision stuff, first turning off the general collision BitMasks.
self.actor.setCollideMask(BitMask32.allOff())
#Then attaching a collision solid to the actor.
self.actorCollider = self.actorNodePath.attachNewNode(CollisionNode("smileyCNode"))
self.actorCollider.node().addSolid(CollisionSphere(0, 0, 0, 1))
#And finally enabling the masks on the collision solid (not the actor itself).
#Wall Mask is used to indicate that objects cannot go into the actor,
#much like the walls themselves.
self.actorCollider.node().setFromCollideMask(self.wallMask)
self.actorCollider.node().setFromCollideMask(self.floorMask)
self.actorCollider.node().setIntoCollideMask(BitMask32.allOff())
#And now, we want a collision ray to be attached to our actor.
self.rayGeometry = CollisionRay(0, 0, 0, 0, 0, -1)
self.actorRay = self.actor.attachNewNode(CollisionNode("actorRay"))
self.actorRay.node().addSolid(self.rayGeometry)
#And then we tell it that it can only collide with the floorMask
#as a From object, and disable it as an Into object, meaning
#no From objects can collide with it.
self.actorRay.node().setFromCollideMask(self.floorMask)
self.actorRay.node().setIntoCollideMask(BitMask32.allOff())
self.physicsHandler.addCollider(self.actorCollider, self.actorNodePath)
self.cTrav.addCollider(self.actorCollider, self.physicsHandler)
#Finally, this will display the collision rays.
self.actorCollider.show()
self.actorRay.show()
#And this will display the collisions.
self.cTrav.showCollisions(render)
#==========
#We also need to disable the mouse, or else our camera controls won't work.
#UNCERTAINTY: Why not?
base.disableMouse()
#==========
#Now we need to assign the collision solids to their respective handlers.
self.floorHandler.addCollider(self.actorRay, self.actorNP)
self.wallHandler.addCollider(self.actorCollider, self.actorNP)
#And now we need to add these colliders to the main traverser.
self.cTrav.addCollider(self.actorRay, self.floorHandler)
self.cTrav.addCollider(self.actorCollider, self.wallHandler)
#==========