Vizard 7 » Reference » Flow control » Actions » Creating your own actions
7.3

Creating Your Own Actions

Actions are useful Vizard constructs that help organize the behavior of nodes and views.  The Vizard API makes it easy to create custom actions to handle your application specific tasks.

 

Actions are classes that inherit from viz.ActionClass.  Actions then have a variety of methods they can override to provide functionality.  Heres a list:

 

begin(self,object)

update(self,elapsed,object)

pause(self,state)

end(self,object)

 

Action classes can also check there current execution state with these methods:

 

finished(self)

paused(self)

Code Examples

Here is how the spin action is implemented:

import viz

class VizSpinAction(viz.ActionClass):
   
    def begin(self,object):
        self.data = self._actiondata_.data
        self.elapsed = 0
        self.duration = self.data[4]
        self.totalAngle = 0
        self.finalAngle = self.duration * self.data[3]

    def update(self,elapsed,object):
        self.elapsed += elapsed
        #If spinning for a finite duration, check if time has passed
        if self.duration > 0.0 and self.elapsed > self.duration:
            self._overtime_ = self.elapsed - self.duration
            object.setAxisAngle(self.data[0],self.data[1],self.data[2],self.finalAngle-self.totalAngle,viz.REL_LOCAL)
            self.end(object)

        else:
            inc = self.data[3]*elapsed
            self.totalAngle += inc
            object.setAxisAngle(self.data[0],self.data[1],self.data[2],inc,viz.REL_LOCAL)

    def spin(x,y,z,speed,dur=viz.FOREVER):
        bla = viz.ActionData()
        bla.data =[x,y,z,speed,dur]
        bla.actionclass=VizSpinAction
        return bla

viz.go()
node = viz.add('logo.wrl')
node.addAction(vizact.spin(0,1,0,90))

Here is an action that rotates an avatar's head to watch a node:

import viz

class WatchNodeAction(viz.ActionClass):
    """Makes avatar head follow node object around"""

    def begin(self,object):
        """Called once when action starts"""

        #Get the node the avatar should look at
        self.nodeToLookAt = self._actiondata_.data[0]
        #Get time the avatar will look at object
        self.duration = self._actiondata_.data[1]
        self.headBone = self._actiondata_.data[2]
        self.blendIn = self._actiondata_.data[3]

        self.timeElapsed = 0

        #Get the head bone and lock it
        self.head = object.getbone(self.headBone)
        self.head.lock()

        self.startQuat = self.head.getQuat()

    def update(self,elapsed,object):
        """Called every frame to update action"""

        self.timeElapsed += elapsed #time avatar has looked at node

        p = self.timeElapsed / self.blendIn

        #If looking for a finite duration, check if time has passed
        if self.duration > 0.0 and self.timeElapsed > self.duration:
            #duration passed, end action
            self.head.lookAt( self.nodeToLookAt.getPosition(), 0, viz.AVATAR_WORLD )
            self.end(object) #End the action and clear it from the action queue

        elif p < 1.0:
            #blend in head look
            self.head.lookAt( self.nodeToLookAt.getPosition(), 0, viz.AVATAR_WORLD )
            targetQuat = self.head.getQuat()

            nextQuad = vizmat.slerp(self.startQuat,targetQuat,p)
            self.head.setQuat(nextQuad)

        else:
            #Done with blend in, just look at node
            self.head.lookAt(self.nodeToLookAt.getPosition(), 0, viz.AVATAR_WORLD)

    def end(self,object):
        if self.head:
            self.head.unlock()
        viz.ActionClass.end(self,object)

#Function to construct the action instance
def watchNode( nodeToLookAt, duration = viz.FOREVER, headBone = 'Bip01 Head', blendIn = .2 ):
    action = viz.ActionData()
    action.data = [ nodeToLookAt, duration, headBone, blendIn ]
    action.actionclass = WatchNodeAction
    return action

viz.go()

viz.MainView.setPosition( 0, 0, 0 )

#Setup ball for the avatar to track
ball = viz.addChild('beachball.osgb',scale=[0.2]*3)

path = viz.addAnimationPath()
points = [ [0,0,1], [-0.3,0,1], [0,0.3,1], [0.3,0,1], [0,-0.3,1], [0,0,1.5], [0,0,1] ]
for x,pos in enumerate(points):
    path.addControlPoint(0.5*x,pos=pos)
path.setLoopMode(viz.LOOP)
path.play()
viz.link(path,ball)

male = viz.add( 'vcc_male.cfg' )
male.setPosition( 0, -1.5, 2 )
male.setEuler( 180, 0, 0 )
male.idlepose(-1)

#Apply the action to the avatar
male.addAction( watchNode(ball, viz.FOREVER) )

def endHeadWatch():
    #blend head to neutral orientation
    head = male.getBone('Bip01 Head')
    headQuat = head.getQuat(viz.AVATAR_LOCAL)
    male.endAction()
    head.lock()
    head.setQuat(headQuat, viz.AVATAR_LOCAL)
    male.addAction( vizact.headto( 0,0,0, 20, bone = 'Bip01 Head'), 1 )

vizact.onkeydown(' ',endHeadWatch)

See also

In this section:

Action Basics

Action synchronization and management

Sequences

Dynamic parameters

Node commands as actions

Actions command table

Other sections:

Tutorial: Using actions

Task basics

Director basics

Timer basics

Animation path basics

Event Basics