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 (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