Ok first programming question: mopaths


#1

Okay I am rewriting a game I wrote in 2d in enigma.

IN the tutorials I saw for panda3d, the first had a series of intervals to make the panda go back and forth. But the manual mentioned later on mopaths, as being splines made in a modeler and exported as an egg.

So is this mopath essentially the same thing as a path an actor follows if so is there a tutorial or example I could see?


#2

I do not know who created the demo to mention the pseudonym. Found an example on the site in the zone RU.

from panda3d.core import *
loadPrcFileData("", "egg-load-old-curves 0")

class NURBSMopath():
   
    def __init__(self, curve, name = None, rotate = False, useEvalTangent = False):
        if (name == None):
            name = 'nurbsmopath'
        self.name = name
        self.duration = 1.0
        self.node = None
        self.loop = False
        self.cnpRef = None
        self.rope = None
        self.evaluator = None
        self.nurbs = None
        self.tDisplace = 0
        self.tCurrent = 0
        self.loopNum = 0
        self.rotate = rotate
        self.useEvalTangent = useEvalTangent
        if curve:
            if isinstance(curve, str):
                self.loadCurves(curve)
            elif isinstance(curve, NodePath):
                self.cnpRef = curve
                self.__extractCurves(curve)
            elif isinctance(curve, RopeNode):
                self.setCurve(curve)
       
    def loadCurves(self, fname):
        if self.cnpRef:
            self.cnpRef.detachNode()
        self.cnpRef = loader.loadModel(fname, noCache=True)
        if self.cnpRef:
            if not self.__extractCurves(self.cnpRef):
                print ('NURBSMopath: can\'t find any curves in file: %s' % fname)
        else:
            print ('NURBSMopath: no data in file: %s' % fname)
           
    def setCurve(self, curve):
            self.rope = NodePath(curve)
            self.evaluator = curve.getCurve()
            self.nurbs = self.evaluator.evaluate()
           
    def __extractCurves(self, np):
        node = np.node()
        if isinstance(node, RopeNode):
            self.setCurve(node)
            return True
        else:
            for ch in np.getChildren():
               if self.__extractCurves(ch):
                   return True
                   
    def __playTask(self, task):
        start, stop = self.getRange()
        delta = stop - start
        scaled_duration = delta * self.duration
        self.loopNum = int(task.time / self.duration)
        if (not self.loop) and (self.loopNum > 0):
            self.finish()
            messenger.send(self.name + '-done')
            self.node = None
            return task.done
        t = self.nurbs.getStartT() + (task.time \
            - (self.loopNum * self.duration)) * delta / self.duration \
            + self.tDisplace
        self.tCurrent = t
        if self.useEvalTangent:
            self.goTo_with_default_rotation(self.node, t)
        else:
            self.goTo(self.node, t)
        return task.cont
       
    def getRange(self):
        if self.nurbs:
            return (self.nurbs.getStartT(), self.nurbs.getEndT())
        else:
            return (0, 0)
    
    def getMaxT(self):
        start, stop = self.getRange()
        return stop
    
    def goTo_with_default_rotation(self, node, t):
        if node:
            p = Point3()
            v = Vec3()
            self.nurbs.evalPoint(t, p)
            self.node.setPos(self.rope, p)
            if self.rotate:
                self.nurbs.evalTangent(t, v)
                v = render.getRelativeVector(self.rope, v)
                node.lookAt(node.getPos() + v)
    
    def goTo(self, node, t):
        if node:
            start, stop = self.getRange()
            delta = stop - start
            p = Point3()
            p0 = Point3()
            self.nurbs.evalPoint(t, p)
            if self.rotate:
                self.nurbs.evalPoint(t + delta*0.001, p0)
                if p == p0:
                    self.nurbs.evalPoint(t - delta*0.001, p0)
                    v = Vec3(p - p0)
                else:
                    v = Vec3(p0 - p)
                #v.normalize()
                node.lookAt(node.getPos() + v)
            node.setPos(self.rope, p)
            
    def play(self, node, duration = 1.0, resume = False, loop = False):
        if self.nurbs:
            if not resume:
                self.lastTime = 0
            self.node = node
            self.duration = duration
            self.loop = loop
            self.stop()
            t = taskMgr.add(self.__playTask, self.name + '-play')
        else:
            print ('NURBSMopath: has no curve.')
       
    def stop(self):
        self.tDisplace = self.tCurrent
        taskMgr.remove(self.name + '-play')
       
    def finish(self):
        start,stop = self.getRange()
        self.tDisplace = 0
        self.tCurrent = 0
        self.lastTime = 0
        self.loopNum = 0
        taskMgr.remove(self.name + '-play')


if __name__ == "__main__":
    from direct.directbase import DirectStart
    from direct.interval.MopathInterval import *
    from direct.interval.IntervalGlobal import *
    
    test_model = loader.loadModel('zup-axis')
    test_model.reparentTo(render)
    test_model.setScale(0.2)
    
    nmps = []
    for i in range(2):
        nmp = NURBSMopath('./nurbs')
        nmp.rope.reparentTo(render)
        nmp.rope.setH(180 * i)
        nmp.rope.setScale(2)
        nmps.append(nmp)
    
    seq = Sequence()
    for nmp in nmps:
        seq.append(MopathInterval(nmp, test_model, name = "Name", duration = 3))
    seq.loop()

    base.disableMouse()
    base.camera.setPos(15,15,15)
    base.camera.lookAt(0,0,0)
    base.run()

Short version:

from panda3d.core import *   
from direct.directbase import DirectStart   
from direct.directutil.Mopath import Mopath   
from direct.interval.MopathInterval import *   
myModel = loader.loadModel('nurbs')   
curveNode = myModel.find("**/+NurbsCurve")   
myMopath = Mopath()   
myMopath.loadNodePath(curveNode)   
myMopath.fFaceForward = True   
myCube = loader.loadModel("yup-axis")   
myCube.setScale(0.1)   
myCube.reparentTo(render)   
myInterval = MopathInterval(myMopath, myCube, duration=10 ,name = "Name")   
myInterval.start()   
base.disableMouse()   
base.camera.setPos(15,15,15)   
base.camera.lookAt(0,0,0)   
base.run()  

Resources and source .blend for demonstration:

nurbs.blend (404.8 KB)
nurbs.egg (848 Bytes)