Checking task state

I’ve got a problem again (not just one but i’ll start with that) :smiley:
Is there any way to check the task state? Some function or sth like that.
I want to have a task queue and be sure that the previous task gave Task.done before next one starts.
Thanks in advance. :smiley:

You can use task.isAlive(), or taskMgr.hasTaskNamed(‘myTask’).


Try task.getState().

EDIT: Oops, drwr wins once again :slight_smile:

Aaargh! I’m missing something ;>

Let’s say, I’ve got FirstTask and I want to add a SecondTask to taskMgr but only if FirstTask is done and removed. So it is supposed to be like this:

taskMgr.add(self.FirstTask, 'First')
if (...)
  taskMgr.add(self.SecondTask, 'Second')

Could you write a missing code fragment in the patenthesis, plz? I don’t want to use doMethodLater. And I DO want to remove done tasks because it affects my frame rate.

Yeah, I’m pretty sure it’s quite simple but I can’t figure it out. :confused:

Perhaps this?

taskMgr.add(self.FirstTask, 'First')
if (not taskMgr.hasTaskNamed('First')):
  taskMgr.add(self.SecondTask, 'Second')

You don’t need to remove ‘First’ anymore, if it’s already done and removed, of course. :slight_smile:

It doesn’t work. It looks like the previous task was never removed. :confused:

EDIT: Ok, it should be easier to show me the way. The code looks like this:

import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from direct.task import Task

class World(DirectObject):
    def __init__(self):
    def First(self, task):
        print 'first'
        return Task.done

    def Second(self, task):
        print 'second'
        return Task.done
    def start(self):
        taskMgr.add(self.First, 'First')
        if (not taskMgr.hasTaskNamed('First')):
            taskMgr.add(self.Second, 'Second')

w = World()

I know it’s stupid but I want to get the idea of task queue.

Your code only checks taskMgr.hasTaskNamed() once. As it happens, at the time you check it, that task is indeed still running (because you just started it).

Some time later, the task finishes, and if you were to call taskMgr.hasTaskNamed() again, you would see that it is no longer in the task queue. But you never call this again, so that doesn’t happen.

But if what you want is for Second to be spawned as soon as First finishes, then why not have First call taskMgr.add(self.Second) just before it returns Task.done? Or, maybe even easier, simply have First call self.Second().


The problem is that both self.First & self.Second have to give the sequence eventually:
fade in picture, wait, fade out. When I call self.Second with self.First the pictures are faded in almost at the same time.
On the other hand when I call:

def start(self):
  taskMgr.add(self.First, 'First')
  taskMgr.doMethodLater(5.0, self.Second, 'Second')

I’m getting frame rate drop from about 250 to 200. If I put more tasks there I get about 100 frames per second in the end. Few more tasks and I’ll get a slide show.

Well, what is your task doing? Does it spawn an interval or something else that actually does the fading, or does it handle the fade itself? If you are handling the fade directly within the task, then calling self.Second() after you have done with the fade would be exactly the right thing to do. If you are spawning something else that handles the fade, though, then you need to arrange for whatever it is you are spawning to call self.Second when it has finished.

Something, somewhere, is managing that fade. Whatever that code is, it knows when it has finished. The smartest thing to do is to have that code be responsible for starting the next step.

If you are using the interval system–and from what you describe, you probably should be, instead of the task system–then you only need to create a Sequence interval that contains the fade in, followed by a wait, followed by the fade out.

If you spawn one task and your frame rate goes from 250 fps (4 ms) to 200 fps (5 ms), it means that your task takes 1 ms to execute. That’s kind of expensive for a task, but it also means you can have about 30 of these tasks running and still be getting 30 fps, or 50 of them running and still be getting 20 fps.

Also, if your frame rate never recovers when the task supposedly finishes, are you sure your tasks really are finishing?


Thanks for an idea. I’ve remade it using intervals and sequence. The permanent framerate drop no longer exists. :smiley:
But there is another problem that occured.
In a simple way my code looks like this:

def loadImage - function which:
  sets the onScreenImage :>
  set its transparency to 1
  runs fade in, wait, fade out sequence.


def loadSequence - which:
  runs Func(loadImage), wait, Func(loadImage), wait, etc.

The problem is that when Func(loadImage) sets the image it appears on a short period of second, just before its transparency is set to 1. Then it disappears and is faded in according to the sequence.
How to eliminate this flashing-image effect?

I don’t think you’ve quite got the concept of a sequence yet. You shouldn’t call a function that spawns another sequence; it should all be embedded in the one sequence.

Something like this:

seq = Sequence(Func(, ColorScaleInterval(self.image, 1, (1, 1, 1, 1)), Wait(2), ColorScaleInterval(self.image, 1, (1, 1, 1, 0)), Func(self.image.hide))


Ok. Thank you for your patience. I did it in other way but quite similar. I have one function which does all the stuff - as you’re saying so in your last reply. ;D
Anyway: one more question (I hope it’s the last one, in this topic at least :D). Do I have to load all OnscreenImages in function (in which that sequence exists) before the beginning of sequence or can I load them dynamically inside the sequence?

You can load them inside your sequence, but you need to have a NodePath to reference when you construct the sequence. So if that NodePath doesn’t exist before you construct the sequence, you can create a dummy NodePath that you operate on, and simply parent the image to that NodePath within your sequence.


Aaaa! I give up. Give me hint, please. It drives me crazy :smiley:

def loadImage(self):
        self.image = OnscreenImage()
        self.dummy_image_node = render.attachNewNode('dummy_image_node')
        Sequence(Func(self.image.setImage, 'Graph/image.PNG'),
                Func(self.image.setTransparency, 1),
                self.image.colorScaleInterval(1, (1, 1, 1, 1)),
                self.image.colorScaleInterval(1, (1, 1, 1, 0)),

Where is my lame mistake? ;>

You can’t do this:

within a Sequence. That’s a direct function call, not an interval. But you can make it an interval, by wrapping it in the Func object, like this:

But, if you are going to create self.image ahead of time, you don’t need to mess with dummy_image_node. You can just do something like this:

self.image = OnscreenImage()
seq = Sequence(Func(self.image.setImage, 'Graph/image.PNG', aspect2d),
                Func(self.image.setTransparency, 1),
                self.image.colorScaleInterval(1, (1, 1, 1, 1)),
                self.image.colorScaleInterval(1, (1, 1, 1, 0)),


The code doesn’t run. I don’t know where’s the problem. It gives an error:

AsserationError: !is_empty() at line 958 of panda/src/pgraph/nodePath.cxx

and a few more.

Ps. I can stay with my present version of function but I just want to clearly understand the idea of intervals, sequences etc.

Ah, you’re right. OnscreenImage reassigns itself when you call setImage(), so you do have to use a dummy parent after all.

self.root = render2d.attachNewNode('root')
self.image = OnscreenImage()
seq = Sequence(Func(self.image.setImage, 'maps/gradient.rgb', self.root),
                Func(self.root.setTransparency, 1),
                self.root.colorScaleInterval(1, (1, 1, 1, 1)),
                self.root.colorScaleInterval(1, (1, 1, 1, 0)),


You rule! Thanks a lot! ! ! :smiley: