Point & Click Turning Bug!

Thanks Russ, I did as you suggested, but now I’m getting a new error message (:evil: it’s enough to make you scream, isn’t it?).

And the new code:

# This program turns a model to the position (point 3) of a left mouse click 
# on a 3d surface.

import direct.directbase.DirectStart # Start Panda 
from pandac.PandaModules import * # Import the Panda Modules
from direct.showbase.DirectObject import DirectObject # To listen for Events
from direct.task import Task # To use Tasks
from direct.actor import Actor # To use animated Actors 
from direct.interval.IntervalGlobal import * # To use Intervals
import math # To use math (sin, cos..etc)
from math import sqrt
import sys  

class Picker(DirectObject): 
    def __init__(self): 
        base.disableMouse()
        # Position the camera
        camera.setPos(0, -35, 18) # X = left & right, Y = zoom, Z = Up & down.
        camera.setHpr(0, -25, 0) # Heading, pitch, roll.
        # Declare variables
        self.position = None
        self.playerMovement = None
        self.movementSpeed = 8.0 # Controls how fast the player moves.
        self.reducedH = None
        # Load an environment
        self.environ = loader.loadModel("MODELS/grass")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)
        self.player = loader.loadModel("MODELS/fleet")
        self.player.reparentTo(render)
        self.player.setPos(0, 0, 0)
        self.player.setHpr(0, 0, 0)
        self.player.setColor(Vec4(0, 148, 213, 1))
        self.npLook = render.attachNewNode("npLook")
        # Declare functions.
        self.reducePlayerH()
        # Setup collision stuff. 
        self.picker= CollisionTraverser() 
        self.queue=CollisionHandlerQueue() 
        self.pickerNode = CollisionNode('mouseRay') 
        self.pickerNP = camera.attachNewNode(self.pickerNode) 
        self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) 
        self.pickerRay = CollisionRay() 
        self.pickerNode.addSolid(self.pickerRay) 
        self.picker.addCollider(self.pickerNode, self.queue)
        # Setup controls
        self.accept("escape", sys.exit) 
        self.accept('mouse1', self.moveToPosition)
        
    def closestDestAngle(src, dest):
        diff = src - dest
        if diff > 180:
            # if the difference is greater that 180 it's shorter to go the other way
            return src - (diff - 360)
        elif diff < -180:
            # or perhaps the OTHER other way...
            return src - (360 + diff)
        else:
            # otherwise just go to the original destination
            return dest

    def reducePlayerH(self):
        # Reduce the players heading to eliminate wrap-around
        reducedH = self.player.getH()%360.0
        self.player.setH(reducedH) 

    def getPosition(self, mousepos):
        self.pickerRay.setFromLens(base.camNode, mousepos.getX(),mousepos.getY()) 
        self.picker.traverse(render) 
        if self.queue.getNumEntries() > 0: 
            self.queue.sortEntries()
            # This is the clicked position. 
            self.position = self.queue.getEntry(0).getSurfacePoint(self.environ) 
            return None
        
    def moveToPosition(self):
        # Get the clicked position 
        self.getPosition(base.mouseWatcherNode.getMouse())
        # Calculate the new hpr
        self.npLook.setPos(self.player.getPos())
        self.npLook.lookAt(self.position) # Look at the clicked position.
        currHpr = self.player.getHpr()
        newHpr = self.npLook.getHpr()
        newH = closestDestAngle(currHpr[0], newHpr[0])
        # Create a turn animation from current hpr to the calculated new hpr.
        playerTurn = self.player.hprInterval(.2, Point3(newHpr[0], newHpr[1], newHpr[2]))
        # Calculate the distance between the start and finish positions.
        # This is then used to calculate the duration it should take to
        # travel to the new coordinates based on self.movementSpeed.
        travelVec = self.position - self.player.getPos()
        distance = travelVec.length()
        # Put the animations into a sequence.
        playerMove = self.player.posInterval((distance / self.movementSpeed), self.position)
        self.playerMovement = Sequence(playerTurn, Func(self.reducedH), playerMove)
        self.playerMovement.start()
        
p = Picker() 

run()

I dunno, maybe I’m just not cut out for this programming business :cry:.

Thanks again