I would have thought that the hpr interval takes the shortest distance to the destination angle…I can adjust for this in code, but is this really the desired output?
import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *
s = loader.loadModel('smiley')
s.reparentTo(render)
s.setH(-90)
s.hprInterval(10,Vec3(180,0,0)).start()
run()
the smiley turns 270 degrees instead of 90 the other way…The way around this is to either turn the -90 into 270 or the 180 to -180, and I can do this with some smart algorithms, but when the values are dynamic it gets a little more complex.
(Also, lerping from 0 to 360 or -180 to 180 results in a full 360 degree turn instead of a zero turn…)
Is this the desired result?
(the easy fix is simply to make sure that everything on the input side is in the range [0,360).
Note that quatInterval can automatically convert your hprs to quaternions:
s.quatInterval(10, hpr = Vec3(180, 0, 0)).start()
Note that this isn’t in fact a fix at all. If the hprInterval constrained all its inputs into [0, 360), it would change the 20-degree lerp from 10 to -10 into a 340-degree lerp from 10 to 350. If you insist on working with Euler angles, the real solution is to use PythonUtil.fitDestAngleToSrc() to match the destination angle to within +/- 180 degrees of the source angle. The hprInterval doesn’t do this automatically, though, because maybe you wanted it to go the long way around. (In fact you can construct a hprInterval that spins several times around before it stops, and this is sometimes useful.)
I had a solution, basically copied straight from gpwiki.net, but it seems much more complicated than the solutions above:
def turnUnit(self, task):
dt = task.getDt()
H = self.model.getH() #self.model is the actor class
T = self.destinationAngle
if T < 0: T = 360.0+T
if H < 0: H = 360.0+H
maxTurn = self.turnSpeed*dt
targetVec = Vec3(math.cos(math.radians(T+270)), math.sin(math.radians(T+270)), 0)
curVec = Vec3(math.cos(math.radians(H+270)), math.sin(math.radians(H+270)), 0)
targetVec.normalize()
curVec.normalize()
xProduct = targetVec.cross(curVec)
if abs(T-H) < maxTurn:
self.model.setH(T)
taskMgr.add(self.moveUnit, self.name+"_movement")
return
if xProduct[2] > 0:
if H-maxTurn < 0:
self.model.setH(360+(H-maxTurn))
else:
self.model.setH(H-maxTurn)
else:
if H+maxTurn > 360:
self.model.setH(H+maxTurn-360)
else:
self.model.setH(H+maxTurn)
return Task.cont
btw although this isn’t done with HprIntervals, I’m sure the same principal appiles.