Few advices, please

Thank you all, gentlemen! Thanks to your advices I figured this out.

(I have asked few other questions related to this code, in this thread: discourse.panda3d.org/viewtopic.php?t=3818)

Another question: in the manual it is said that Roaming Ralph uses very inefficient collision method in order to update Ralph’s Z coordinate. What collision method is better? Where can I find better samples and study them?

In order to help newbies like me in future, here I post the working code with commentaries:

# This code was created with Crimsonland-like shooter concept in my head.
# This is why I placed camera so high and removed camera collisions. They
# can be easily restored, having the original Roaming Ralph sample
# and this code.
# Thanks to all who help to make this code!

import direct.directbase.DirectStart

from direct.actor.Actor import Actor
from direct.showbase.DirectObject import DirectObject
from direct.task.Task import Task
from pandac.PandaModules import WindowProperties
from pandac.PandaModules import PandaNode,NodePath,Camera,Vec3,Filename

from pandac.PandaModules import CollisionTraverser,CollisionNode
from pandac.PandaModules import CollisionHandlerQueue,CollisionRay,BitMask32

import sys

# Path to Roaming Ralph's models directory
modelsDir = "Roaming-Ralph/models/"

# Ralph's speed, units per second
speed = 3

class World(DirectObject):

    def __init__(self):

        # Disable defaul camera controls
        base.disableMouse()

        # Initial setup
        props = WindowProperties()
        props.setCursorHidden(True)
        base.win.requestProperties(props)
        base.setBackgroundColor(0, 0, 0)

        # Find the center of the screen
        self.screenCenterX = base.win.getProperties().getXSize()/2
        self.screenCenterY = base.win.getProperties().getYSize()/2

        # Move mouse to the middle of the screen
        base.win.movePointer(0, self.screenCenterX, self.screenCenterY)

        # Game state variables
        # Previous recorded time in milliseconds (will be used for movements)
        self.prevtime = 0
        # Is Ralph moving now? (will be used to animate Ralph)
        self.isMoving = False

        # Initial orientation of Ralph, floater, and camera
        # (i.e. self.actorPlace) in degrees
        self.angle = 0

        # Set floater and camera position (relative to self.actorPlace).
        # The camera will look at the floater, and not at Ralph himself.
        # Right(-) or left(+), forward (-) or backward (+), down(-) or up(+)
        self.floaterPos = (0, -2, 1)
        self.cameraPos = (0, 15, 10)

        # When we scale nodes, their local coordinate system is scaled too.
        # Also, some models use Y as top-down axis, while the engine uses Z
        # for it. Therefore, in order to avoid confusion, it's better to
        # create an empty node (here it's called "actorPlace"), and reparent
        # Ralph to it. In this case Ralph can be scaled as he needs,
        # and have Y as his top-down axis, still, we can move, rotate or use
        # him in any other way with ease

        # Create Actor's placeholder
        self.actorPlace = NodePath(PandaNode("actorPlace"))
        self.actorPlace.reparentTo(render)
        self.actorPlace.setPos(0, 0, 0)
        self.actorPlace.setHpr(self.angle, 0, 0)

        # Create the main character, Ralph, with two animations
        # and reparent him to the self.actorPlace
        self.ralph = Actor(modelsDir+"ralph",
                                 {"run":modelsDir+"ralph-run",
                                  "walk":modelsDir+"ralph-walk"})
        self.ralph.reparentTo(self.actorPlace)
        self.ralph.setScale(.2)
        self.ralph.setPos(0, 0, 0)
        self.ralph.setHpr(0, 0, 0)

        # Create the floater and reparent it to the self.actorPlace
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.actorPlace)
        self.floater.setPos(self.floaterPos[0], self.floaterPos[1], self.floaterPos[2])

        # Create the camera, reparent it to the self.actorPlace
        # and make it look at the floater
        base.camera.reparentTo(self.actorPlace)
        base.camera.setPos(self.cameraPos[0], self.cameraPos[1], self.cameraPos[2])
        base.camera.lookAt(self.floater)

        # Load world
        self.environ = loader.loadModel(modelsDir+"world")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)

        # Create key map
        # (primFire and secFire are not used, but reserved for future use)
        self.keyMap = {"left":0,
                       "right":0,
                       "forward":0,
                       "backward":0,
                       "changeView":0,
                       "primFire":0,
                       "secFire":0}

        # Accept the control keys for movement and rotation
        # (primFire and secFire are not used, but reserved for future use)
        self.accept("escape", sys.exit)
        self.accept("w", self.setKey, ["forward",1])
        self.accept("a", self.setKey, ["left",1])
        self.accept("s", self.setKey, ["backward",1])
        self.accept("d", self.setKey, ["right",1])
        self.accept("w-up", self.setKey, ["forward",0])
        self.accept("a-up", self.setKey, ["left",0])
        self.accept("s-up", self.setKey, ["backward",0])
        self.accept("d-up", self.setKey, ["right",0])
        self.accept("mouse2", self.setKey, ["changeView",1])
        self.accept("mouse2-up", self.setKey, ["changeView",0])
        self.accept("mouse1", self.setKey, ["primFire",1])
        self.accept("mouse1-up", self.setKey, ["primFire",0])
        self.accept("mouse3", self.setKey, ["secFire",1])
        self.accept("mouse3-up", self.setKey, ["secFire",0])

        # We repeat self.move every frame
        taskMgr.add(self.move,"moveTask")

        # Collision detection
        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)

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    def move(self, task):
        # This method is called every frame, since it is attached to taskMgr.

        # The elapsed time is the current time minus the last saved time
        elapsed = task.time - self.prevtime

        # Save Ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.
        startpos = self.actorPlace.getPos()

        # If a move key is pressed, turn ralph in the specified direction.
        if (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0) or (self.keyMap["forward"]!=0):
            rotDirections = (self.keyMap["left"], self.keyMap["right"], self.keyMap["backward"], self.keyMap["forward"])
            rotValues = (90, 270, 180, (0, 360))
            rotateBy = 0
            divideBy = 0
            for direction in rotDirections:
                divideBy += direction
            for value in range(0, 4):
                if value != 3:
                    rotateBy += rotDirections[value]*rotValues[value]
                if value == 3:
                    if self.keyMap["left"]!=0:
                        rotateBy += rotDirections[value]*rotValues[value][0]
                    else:
                        rotateBy += rotDirections[value]*rotValues[value][1]
            rotateBy = rotateBy / divideBy
            self.ralph.setH(rotateBy)

        # If a move-key is pressed, move ralph in the specified direction.
        if (self.keyMap["left"]!=0):
            self.actorPlace.setPos(self.actorPlace, Vec3(1, 0, 0)*(elapsed*speed))
        if (self.keyMap["right"]!=0):
            self.actorPlace.setPos(self.actorPlace, Vec3(-1, 0, 0)*(elapsed*speed))
        if (self.keyMap["forward"]!=0):
            self.actorPlace.setPos(self.actorPlace, Vec3(0, -1, 0)*(elapsed*speed))
        if (self.keyMap["backward"]!=0):
            self.actorPlace.setPos(self.actorPlace, Vec3(0, 1, 0)*(elapsed*speed))

        # If ralph is moving, loop "run" animation.
        # If he is standing still, stop the animation.
        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0):
            if not self.isMoving:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        # Mouse controls
        if self.keyMap["changeView"]!=0: # If changeView button is pressed, change view when moving mouse.
            mouseX = base.win.getPointer(0).getX()
            # Update ratation
            if base.win.movePointer(0, self.screenCenterX, self.screenCenterY):
                self.angle -= (mouseX - self.screenCenterX)
            if self.angle < 0:
                self.angle += 360
            if self.angle >= 360:
                self.angle -= 360
        # Otherwise, just keep cursor position at the center of the screen
        else:
            base.win.movePointer(0, self.screenCenterX, self.screenCenterY)

        # Update actorPlace orientation
        self.actorPlace.setH(self.angle)

        # 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.actorPlace.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.actorPlace.setPos(startpos)

        # Store the task time and continue
        self.prevtime = task.time
        return Task.cont

# Create world
World()
run()