Problem with tasks

This is the first time I’m using tasks in a script, and I’m having some trouble getting the task to do what I want. What I want to do is to have a couple of sequences wait six seconds before playing. I’m not sure exactly what I’m doing wrong, but I’ll blame it on inexperience for now. Basically the sequences make the airbladepilot model wave his left hand. Here’s the code:

 
import direct.directbase.DirectStart

from direct.task import Task
from direct.actor import Actor
from direct.interval.IntervalGlobal import *
from direct.showbase.DirectObject import DirectObject


class World(DirectObject):
    def __init__(self):
        #create an actor node, load a model and animation, and set it to be rendered
        self.pilot = Actor.Actor()
        self.pilot.loadModel('airbladepilot/pilot-model')
        self.pilot.reparentTo(render)
        self.pilot.loadAnims({'rar':'airbladepilot/pilot-newidle'})

        self.pilot.setPos(0,130,-30)

        #create the shoulder, elbow, and wrist nodes, to control the arm
        self.shoulder = self.pilot.controlJoint(None,'modelRoot', 'Bone_l_arm_upper')

        self.elbow = self.pilot.controlJoint(None, 'modelRoot', 'Bone_l_arm_lower')
        self.wrist = self.pilot.controlJoint(None, 'modelRoot', 'Bone_l_hand')

        #set intervals for animating the elbow and wrist(similar to keyframes)
        self.e_interval1 = self.elbow.hprInterval(2, Point3(42.42,15,90))
        self.e_interval2 = self.elbow.hprInterval(2, Point3(42.42,-15,90))



        self.w_interval1 = self.wrist.hprInterval(2, Point3(33, -25.26, 30.76))
        self.w_interval2 = self.wrist.hprInterval(2, Point3(-17.08, -25.26, 30.76))

        #create sequence nodes consisting of the previously defined intervals
        self.e_sequence = Sequence(self.e_interval1, self.e_interval2)
        self.w_sequence = Sequence(self.w_interval1, self.w_interval2)
                    
        #loop pre-made animation
        self.pilot.loop('rar')

        #list names of joints the modeler created
        self.pilot.listJoints()
        
        taskMgr.doMethodLater(6, self.play, 'play')
        taskMgr.add(self.blah, 'blah')
        
    def play(self, task):
        
        #set starting position of the arm
        self.elbow.setHpr(42.42, -15, 90)
        self.shoulder.setHpr(0,0,0)

        #play the sequences 
        self.e_sequence.start()
        self.w_sequence.start()
        
        return Task.cont
    
    def blah(self, task):
        #print the task time over and over again (for testing)
        t = task.time
        print t
        return Task.cont
        
c = World()
#run Panda
run()

It’s probably very sloppy as far as code goes, my goal right is to just get the animation to play by means of a task. Thanks!

Update: I managed to get it working by using an if statement:


if (task.time >12.9) & (task.time < 13.1):
    self.e_sequence.loop()
    self.w_sequence.loop()
return Task.cont

I don’t understand why the statement is necessary though, if someone knows why it’d be very helpful, thanks again.

What your trying to do here is kind of strange. It seems like your trying to do joint manipulation while an actor is playing an animation. Frankly, this is never suppose to be done.

Basically your calling looping an idle animation that is updating the model’s bone positions at every frame. Then when you call a sequence to start another bone manimulation, it changes it for one frame and then goes back to the looping idle animation. When you put the sequence in a loop essentially it was overriding the actor animation. This is probably dangerous and may not work all the time.

What you want is partial skeleton animations. Unfortunately, although this has been implemented, there is no documentation of this feature as of yet. You can try to figure it out by looking at the API for actor here:
panda3d.org/apiref.php?page=Actor

Also for the do method later sequences. There is a Wait sequence. You can actually structure your sequences like this:

a = Sequence(Wait(1), …)

It’s my understanding that an animation has to be playing on a joint for controlJoint to work properly, that’s the reason for the animation. What happens when the sequences are looped is that the animation continues to play on the joints unaffected by the controlJoint calls, while the procedural animation plays in the desired joints.

When the idle animation is not started (using play() or loop()), controlJoint does not work. When play() is used, controlJoint still works after the animation has stopped. That’s what happens under my (limited) experience. What I am still confused about is why the sequences do not play when they are included in a task straight up, but they do when they are under an if statement.

Try changing the return statement of your play() method from:


        return Task.cont

To:


        return Task.done

The problem with returning Task.cont is that it means the play() method will be called again next frame, and again and again and again, so the interval is constantly being restarted, and never gets a chance to play.

Note that if your only purpose is to introduce a six-second delay before the interval begins, you can do this more easily by putting a Wait(6) in the beginning of the interval, and then starting it immediately.

David