triggers, interactive map, volumetric effect, noGo zones

I finally got my character to have some interaction with the environment, thought I’d share it with others. The below code is just the most relevant portions. Some notes, I modeled a spinning platform in Blender as a cylinder. Likewise, I made a saw blade. I changed the names from the default name (cylinder) to sawBlade and spinningPlatform which is important for collision detection. I made a grid as the floor and renamed it Floor. I edited their egg files to include sawBlade {keep polyset descend}. I also made a cube which I used as the player. I did not add a collision node to this. If you add a collision node, the collision ray will hit it. But now that I think about it I guess I could get away with this by changing

            firsthit = self.rayToGroundHandler.getEntry(0)

to

            firsthit = self.rayToGroundHandler.getEntry(1)

Its set up so that when the player hits the sawBlade their position just gets reset to zero but this could be easily changed to have a decrease in health or play an animation or whatever. When the player steps on the spinning platform, they stick to it (like standing on a merry go round). But they can still walk off.

This technique can be easily extended. If I create a box in Blender and flatten it and rename it lava… or if I make a box and rename it water and set its alpha low, it can be used to start a swim animation. This reminds me of triggers in some level editors. Another box could be made and named LandMine which would start a projectile interval, throwing the player into the air. Or the box could be named trap, causing a trap door in the floor to open or a rock to fall from the sky. Or the walls could move in to crush the player. A platform elevator can be created. A teleporter.

This code also allowed my player to go up steps. The height limit of he step can be contolled by lowering the z value in the code below:

self.toGroundRay.setOrigin(0,0,10)

To prevent the character from going certain places I’ve inserted :

if self.name != "noGoZone":

into my character control code:

    def forwardT (self,task):
        
        if self.name != "noGoZone":
            radians = self.player.getH()*math.pi/180.0
            self.player.setX(self.Icube.getX()-1*math.sin(radians))
            self.player.setY(self.Icube.getY()+1*math.cos(radians))
        return Task.cont

Here is the core code:

class World (DirectObject):
    def __init__(self):
       
...
        #set up my floor
        self.floor = loader.loadModel('floor')
        self.floor.reparentTo(render)
        self.floor.setPos(0,0,0)
        self.floor.setScale(2)
        
          
        #set up a player
        self.player = loader.loadModel('box')
        self.player.reparentTo(render)
        self.player.setPos(0,0,0)

        self.saw = loader.loadModel('saw3')
        self.saw.reparentTo(render)
        self.saw.setPos(20,0,0)

        self.spinner = loader.loadModel('spinner')
        self.spinner.reparentTo(render)
        self.spinner.setPos(-20,0,0)

        
....
        
        self.makeGroundRayF()
        
        
        taskMgr.add(self.stickT, "stickT")
        taskMgr.add(self.rotateT, "rotateT")
        
    def rotateT(self,task):
        self.saw.setH(self.saw.getH()+1)
        self.spinner.setH(self.spinner.getH()+1)
        return Task.cont
    
    def makeGroundRayF(self):
        self.cTrav = CollisionTraverser()
        self.toGroundRay = CollisionRay()
        self.toGroundRay.setOrigin(0,0,10)
        self.toGroundRay.setDirection(0,0,-1)
        self.rayNode = CollisionNode('RayNode')
        self.rayNode.addSolid(self.toGroundRay)
        self.rayNode.setFromCollideMask(BitMask32.bit(0))
        self.rayNode.setIntoCollideMask(BitMask32.allOff())
        self.rayNodePath = self.Icube.attachNewNode(self.rayNode)
        self.rayToGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.rayNodePath, self.rayToGroundHandler)
        self.rayNodePath.show()
        self.cTrav.showCollisions(render)
        
        
        
    def stickT(self, task):
        self.cTrav.traverse(render)
        
        self.rayToGroundHandler.sortEntries()
        if self.rayToGroundHandler.getNumEntries() > 0:
            firsthit = self.rayToGroundHandler.getEntry(0)
            self.name = firsthit.getIntoNode().getName()

            if self.name == "sawBlade": self.player.setPos(0,0,0)
            elif self.name == "spinningPlatform": 
                self.player.wrtReparentTo(self.spinner)
                self.player.setZ(firsthit.getSurfacePoint(render).getZ())
            elif self.name == "Floor":
                self.player.wrtReparentTo(render)
                self.player.setZ(firsthit.getSurfacePoint(render).getZ())

        return Task.cont