Functions and Intervals and Frames

Have a look at the code:

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *

def make( name ):
	return loader.loadModel("/usr/share/panda3d/models/%s" % name)

def cam_thang():
	base.disableMouse()
	camera.setPos(0,-100,0)
	camera.setHpr(0, 0, 0)
	base.camLens.setFar(9000)
	base.camLens.setFov(55)

def follow():
	#The func I propose to call on certain keyframes.
	pass

def actions(t):
	## got a float: t
	## It looks like this:
	## 7.97699987888                                                          
	## 7.99300014973                                                          
	## 8.00999999046                                                          
	## 8.0269998312
	##
	## Yay...
	## I can timeframe=int(t) it. Now I have:
	## 7,7,8,8
	## So it would fire twice on 7 and twice on 8
	## (actually more than that, but this is a sample)
	##
	## Now I have to 'remember' what timeframe I have 'used' before
	## so that I only do func=actionkeys[ timeframe ] once.
	## That means some kind of list or blah...
	##
	#func = actionkeys[ voodoo ] if voodoo in actionkeys
	#if func: func()
	pass

cam_thang()

top = render.attachNewNode("node1")

s1 = make("smiley")
s1.reparentTo(top)
s2 = make("smiley")
s2.reparentTo(top)

poskeys={"start":Point3(-20,0,0), "end":Point3(20,0,0) }
## A dict to hold when (times/keyframes) and what functions to call.
actionkeys={5:follow, 10:follow, 15:follow, 20:follow }

posi = LerpPosInterval( s2, duration=20, pos=poskeys["end"], startPos=poskeys["start"])
acti = LerpFunc( actions, fromData = 0, toData = 20, duration = 20,
             blendType = 'noBlend', extraArgs = [], name = None)

go = Parallel( posi, acti )

go.start()


run()

I have remarked the action function, but the gist is:
I want “actions” (funcs) to happen on set keyframes (integer seconds). This happens in parallel with any other transforms. I am not sure how best to have action() visited properly and how to tell if I am on a unique whole second - like a beat per second: dum, dum, dum.

I could also go for some kind of percentage system, where I would specify that at 5% X happens, at 11% Y happens etc. Dunno if that may be easier than an int() of time.

Any clues?

\d

If you would like the function to be called on integer seconds, why not code it in an interval like this:

Sequence(Func(myfunc), Wait(1), Func(myfunc), Wait(1), Func(myfunc))

Or, you can use the lesser-known Track type interval, which accepts a pair of tuples of the form (time, ival), which means to start the ival at the indicated time in seconds:

Track((0, Func(myfunc)), (1, Func(myfunc)), (2, Func(myfunc)))

Or, simply use a task:

taskMgr.doMethodLater(1, myfunc, 'myfunc')
def myfunc(task):
    ...
    return task.again

David

What I am aiming towards is a timeline control (with frames across and layers down) that contains keyframes that let a user control tweening (lerping) of various attributes. So I need to aim for something generic. My code above is the start to that by using dicts to contain crude keyframe data.

Thanks for that suggestion, I may be able to use it.

Even better…

I don’t know why I have this irational problem with that method. I need to play around somewhat.

The thing is I will need to switch these tasks/lerps on and off as timelines hit blank keyframes or ‘stop’ actions (or ‘goPlay’ actions – which is a jump) and it becomes important to manage things.

Each node in the SG (that is a player) will be controlled by its own dict (or class) that checks its own timeline for what comes next.

I liked the idea of a Sequence of Parallels because that means I can scan the timeline (before starting the whole animation) and build a Seq(Par()) of all the keyframes and actions in them.

BTW, is there any way to stop a seq or parallel? The docs all say “undocumented” right now. pause() seems likely. :slight_smile:
ABTW, is there a way to stop and remove a seq/par?

Thanks, there’s no right and wrong at this stage – I am only moving smileys around right now, trying to find a shape to my thoughts.

Thanks,
\d

Use finish() or pause() to stop any kind of interval. pause() will stop it at the current point, finish() will put it at the ending state and stop.

A related question:
Can a parent node pause/finish the lerps & other intervals (tasks) going on in children?

For example, a car. If I pause the car does it pause the wheels (children with their own lerps) ?

Another angle is if I hide the car, how would I stop the wheels?

I am hoping there’s a Panda-side thing for this, like the way attributes etc. are inherited by children. Otherwise I am looking at some event or pubsub kind of solution.

\d

Intervals are not intrinsically tied to nodes. You can have an interval controlling the car, and a different interval spinning the wheels; and pausing the one will not automatically pause the other, even if the wheels are parented to the car. (But this is a silly example. If you really want to move a car and spin the wheels at the same time, you should probably build a single interval that encapsulates both motions, and then you can pause that one interval.)

Similarly, if you hide the car, you’re still responsible for stopping its intervals independently. You can certainly use Panda’s global event system to make this association more automatic.

David

Thanks all. I think I have enough here to start cooking something.

\d