Best way to implement a time delay

I’ve tried several ways to implement a delay in game:


import time
time.sleep(sometime)

stupid of me, this actually stops the engine’s brain i found out. hehehe


from threading import Timer

t = Timer(2, self.next_player)
t.start()

This way works, but the execution continues, and the timer is created in a separate thread.

Now my question, is there any way that I can create a blocking delay, but with the panda engine still rendering whatever is currently “playing” in the scene?

Thanks!

Sounds like you want a Task, or at least a doMethodLater:


taskMgr.doMethodLater(delayTime, self.myFunction, 'taskName')

In this example, you should declare myFunction to accept one parameter (in addition to self), called task. You can ignore this additional parameter. This function will get called after the delayTime has expired. Put your followup code there. Also see https://www.panda3d.org/manual/index.php?page=task1.

Alternatively, you might want to use an Interval, which is a way to have a totally scripted series of actions take place over a period of time. See https://www.panda3d.org/manual/index.php?page=interval1.

David

But wouldn’t that be the same as:


from threading import Timer
t = Timer(delaytime, functionname)
t.start()

What I was curious about was whether a “blocking timedelay” could be possible, something like this:


label = DirectLabel(text="You just lost 100 dollars")
base.idle(2) # made up, but the execution "stops" here until 2 seconds later
label.destroy() # 2 seconds later, the execution continues to here

Do you know what I mean? Or am I daydreaming? hehehe…
Now that I think of it, it probably isn’t possible.

Thanks dave. :wink:

It’s actually not the same thing as using threading, because the Panda Task system is a cooperative system, implemented in a single thread. It therefore avoids all of the synchronicity and race-condition problems you traditionally have dealing with multiprogramming.

What you’re really asking for is the ability to block the current Task for a length of time and resume later, while allowing other Tasks to continue. That’s exactly what doMethodLater does, with the caveat that you have to pick up where you left off in a different function, which means you need to be resposible for saving all your relevant state (but you can pass arbitrary arguments to the callback method). Although it sounds clumsy, with this system it is actually quite easy to do anything that you would have done with your hypothetical blocking delay function. For instance, to take your example:

label = DirectLabel(text="You just lost 100 dollars")
taskMgr.doMethodLater(2, destroyLabel, 'destroyLabel', extraArgs=[label])

def destroyLabel(label):
  label.destroy()

David

Oh yeah–the implicit assumption is that the calling function–the one that created the label–is also running in its own Task, and that it simply returns, ending its task. Execution of that particular Task need not continue.

When you start using event-driven programming, you will put everything in one task or another, or as a callback on events (such as user input responses), or within an Interval. This is the normal way to design a gui-based interactive program. There’s no longer a single “main” thread of execution that must be paused and resumed.

David

Cool! Thanks for the pointer on the extraArgs parameter and the explanation.