With viztask, you can pause the execution of a function while waiting for some condition, like a few seconds to pass, without blocking the Vizard main loop or spawning an operating system thread.
The viztask module and viz.director functions have similar functionality; however, there are important differences. Calling viz.director actually creates a new thread, while scheduling a task does not. This means that calling a long blocking operation in a task will block the Vizard update loop as well and the frame rate will go to zero. However, in most cases, tasks should be used because they are much more CPU/memory efficient and are non-preemptive so synchronization locks are not necessary.
Any function that is passed to the scheduler must have a yield statement within it. This line tells the program to stop until a condition has been met. There are a number of predefined conditions that tasks can wait for. Check out the yield conditions in the Tasks command table for a list. In the following example, <viztask>.addAction adds the fading action to the ball and waits for that action to be completed before moving to the next line in the scheduled function.
import viztask
ball = viz.add('soccerball.ive')
def fadeAndAppear():
yield
viztask.addAction( ball, vizact.fadeTo(0,time=2) )
print
'done fading'
yield
viztask.addAction( ball, vizact.fadeTo(1,time=2) )
print
'done appearing'
viztask.schedule( fadeAndAppear() )
To run a task repeatedly, just use standard loop statement (while or for). If you want to stop a looping task, kill it with <viztask:Task>.kill.
import viztask
ball = viz.add('soccerball.ive')
def bigAndSmall():
while
True:
yield viztask.waitTime( 1
)
ball.setScale( 2,2,2 )
yield viztask.waitTime( 1
)
ball.setScale( 1,1,1 )
myTask = viztask.schedule( bigAndSmall() )
vizact.onkeydown( ' ', myTask.kill )
If your task yields for an event and you need to get data from that event, use a viz.Data object to hold the data and <viztask>.waitEvent. This condition will work for standard or custom events. Check out the Event reference for standard events or the Custom events section for more on making your own kind of event. Here's an example that yields to any keydown event and then uses the returned key to proceed.
import viztask
text = viz.addText(' ', viz.SCREEN)
text.setPosition(.5,.5)
def showLetter():
while
True:
#Instantiate
a data object.
dataObject = viz.Data()
yield viztask.waitEvent( viz.KEYDOWN_EVENT, dataObject )
#Change
the text with the returned data array.
text.message( dataObject.data[0] )
yield viztask.addAction( text, vizact.fadeTo(0,begin=1,time=1) )
viztask.schedule( showLetter() )
If you want to create a custom condition for your yield statement, write a viztask.Condition class. The update function within this class will generally be called once per frame. When it returns True, the scheduler will continue. In the following example, the up-arrow key moves the ball upwards until it reaches one meter, and then repositions it at zero. Here, waitHigh is the custom condition. It returns True when the object reaches the specified height. The scheduled function then proceeds.
import viztask
ball = viz.add( 'white_ball.wrl' )
vizact.onkeydown( viz.KEY_UP, ball.setPosition, [0,.2,0], viz.REL_PARENT
)
def limitHeight():
myCondition = waitHigh(1, ball)
while
True:
yield myCondition
print 'too high'
ball.setPosition([0,0,0])
class waitHigh( viztask.Condition ):
def
__init__( self, height_limit,
node ):
self.__limit = height_limit
self.__node = node
def
reset( self ):
#Reset
from the current height of the ball.
self.__currentLimit = self.__node.getPosition()[1] + self.__limit
def
update( self ):
#This
function will run about every frame, returning True or False
#to the
yield statement.
return self.__currentLimit <= self.__node.getPosition()[1]
viztask.schedule( limitHeight() )
You can embed sub tasks within a scheduled task. For example, doTrial is scheduled within executeExperiment. The parent task waits for the sub task to finish before it continues.
Signal objects are useful for communicating between tasks. Tasks can either wait for, or send, signals. In the following example, one ball waits for the signal to change color while the other ball sends out the signal between actions.