Point & Click Turning Bug!

Bummer! I’ve tried everything I can think of, I even tried defining ‘closestDestAngle’ as a function in my own code so that I could play with its values, but all to no effect.

I’m at my wit’s end here, it just seems to be an impossible task to get this working properly. I’m beginning to suspect that Panda3D might simply not be capable of implementing point & click game controls :cry: (sadly, a lot of engines can’t).

I’ve tried searching the internet for some type of point & click example codes (even ones written in another language, just to give me some idea of what to do) but I couldn’t find anything of use. Grrr I just don’t know what else to do.

Anyway, here is my ‘almost’ working 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.
        # 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") 
        # 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 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, playerMove)
        reducedH = self.player.getH()%360.0
        self.player.setH(reducedH)
        self.playerMovement.start()
        
p = Picker() 

run()

Cheers