Browse Source

added new projectile mode: pass through waypoint and end on a plane

Darren Ranalli 21 years ago
parent
commit
9bf6494bc1

+ 52 - 17
direct/src/interval/ProjectileInterval.py

@@ -26,12 +26,13 @@ class ProjectileInterval(Interval):
     def __init__(self, node, startPos = None,
                  endPos = None, duration = None,
                  startVel = None, endZ = None,
+                 wayPoint = None, timeToWayPoint = None,
                  gravityMult = None, name = None):
         """
         You may specify several different sets of input parameters.
         (If startPos is not provided, it will be obtained from the node's
         position at the time that the interval is first started. Note that
-        in this case you must provide a duration.)
+        in this case you must provide a duration of some kind.)
         
         # go from startPos to endPos in duration seconds
         startPos, endPos, duration
@@ -39,6 +40,9 @@ class ProjectileInterval(Interval):
         startPos, startVel, duration
         # given a starting velocity, go until you hit a given Z plane
         startPos, startVel, endZ
+        # pass through wayPoint at time 'timeToWayPoint'. Go until
+        # you hit a given Z plane
+        startPos, wayPoint, timeToWayPoint, endZ
         
         You may alter gravity by providing a multiplier in 'gravityMult'.
         '2.' will make gravity twice as strong, '.5' half as strong.
@@ -58,8 +62,8 @@ class ProjectileInterval(Interval):
                 name += '-%s:%s:%s' % (file, line, func)
             """
 
-        args = (startPos, endPos, duration,
-                startVel, endZ, gravityMult)
+        args = (startPos, endPos, duration, startVel, endZ,
+                wayPoint, timeToWayPoint, gravityMult)
         self.implicitStartPos = 0
         if startPos is None:
             if duration is None:
@@ -77,6 +81,7 @@ class ProjectileInterval(Interval):
     def __calcTrajectory(self, startPos = None,
                          endPos = None, duration = None,
                          startVel = None, endZ = None,
+                         wayPoint = None, timeToWayPoint = None,
                          gravityMult = None):
         if startPos is None:
             startPos = self.node.getPos()
@@ -89,8 +94,10 @@ class ProjectileInterval(Interval):
                 result.append(item)
             return result
 
-        startPos, endPos, startVel, endZ, gravityMult = \
-                  doIndirections(startPos, endPos, startVel, endZ, gravityMult)
+        startPos, endPos, startVel, endZ, gravityMult, wayPoint, \
+                  timeToWayPoint = \
+                  doIndirections(startPos, endPos, startVel, endZ, gravityMult,
+                                 wayPoint, timeToWayPoint)
 
         # we're guaranteed to know the starting position at this point
         self.startPos = startPos
@@ -112,10 +119,31 @@ class ProjectileInterval(Interval):
             return PythonUtil.solveQuadratic(accel * .5, startVel,
                                              startHeight-endHeight)
 
+        def calcTimeOfLastImpactOnPlane(startHeight, endHeight,
+                                        startVel, accel):
+            time = calcTimeOfImpactOnPlane(startHeight, endHeight,
+                                           startVel, accel)
+            if not time:
+                return None
+            if type(time) == type([]):
+                # projectile hits plane once going up, once going down
+                # assume they want the one on the way down
+                self.notify.debug('projectile hits plane twice at times: %s' %
+                                  time)
+                time = max(*time)
+            else:
+                self.notify.debug('projectile hits plane once at time: %s' %
+                                  time)
+            return time
+
+        # now all we need is startVel, duration, and endPos.
+
         # which set of input parameters do we have?
         if (None not in (endPos, duration)):
             assert not startVel
             assert not endZ
+            assert not wayPoint
+            assert not timeToWayPoint
             self.duration = duration
             self.endPos = endPos
             self.startVel = calcStartVel(self.startPos, self.endPos,
@@ -123,32 +151,39 @@ class ProjectileInterval(Interval):
         elif (None not in (startVel, duration)):
             assert not endPos
             assert not endZ
+            assert not wayPoint
+            assert not timeToWayPoint
             self.duration = duration
             self.startVel = startVel
             self.endPos = self.__calcPos(self.duration)
         elif (None not in (startVel, endZ)):
             assert not endPos
             assert not duration
+            assert not wayPoint
+            assert not timeToWayPoint
             self.startVel = startVel
-            time = calcTimeOfImpactOnPlane(self.startPos[2], endZ,
-                                           self.startVel[2], self.zAcc)
-            if not time:
+            time = calcTimeOfLastImpactOnPlane(self.startPos[2], endZ,
+                                               self.startVel[2], self.zAcc)
+            if time is None:
                 self.notify.error(
                     'projectile never reaches plane Z=%s' % endZ)
-            if type(time) == type([]):
-                # projectile hits plane once going up, once going down
-                # assume they want the one on the way down
-                self.notify.debug('projectile hits plane twice at times: %s' %
-                                  time)
-                time = max(*time)
-            else:
-                self.notify.debug('projectile hits plane once at time: %s' %
-                                  time)
             self.duration = time
             self.endPos = self.__calcPos(self.duration)
+        elif (None not in (wayPoint, timeToWayPoint, endZ)):
+            assert not endPos
+            assert not duration
+            assert not startVel
+            # we pass through wayPoint at time 'timeToWayPoint', and we
+            # stop when we reach endZ
+            self.startVel = calcStartVel(self.startPos, wayPoint,
+                                         timeToWayPoint, self.zAcc)
+            self.duration = calcTimeOfLastImpactOnPlane(
+                self.startPos[2], endZ, self.startVel[2], self.zAcc)
+            self.endPos = self.__calcPos(self.duration)
         else:
             self.notify.error('invalid set of inputs to ProjectileInterval')
 
+        # these are the parameters that we need to know:
         self.notify.debug('startPos: %s' % `self.startPos`)
         self.notify.debug('endPos:   %s' % `self.endPos`)
         self.notify.debug('duration: %s' % self.duration)

+ 14 - 0
direct/src/interval/ProjectileIntervalTest.py

@@ -0,0 +1,14 @@
+from pandac.PandaModules import *
+from direct.directbase.DirectStart import *
+from IntervalGlobal import *
+
+smiley = loader.loadModel('models/misc/smiley')
+smiley.reparentTo(render)
+
+def doTest():
+    pi = ProjectileInterval(smiley, startPos=Point3(0,0,0),
+                            endZ = -10, wayPoint=Point3(10,0,0),
+                            timeToWayPoint=3)
+    pi.loop()
+    return pi
+