bharling

29-01-2009 14:29:06

Danaugrs

30-01-2009 17:18:53

Love it!

I was just looking for something like that!

I began to think I had to write my own interpolation module sometime ago,

when I realized how code/time consuming creating interpolations manually was.

But I never really implemented the idea.

Very useful indeed!

Cheers,

Danaugrs

bharling

31-01-2009 10:42:51

Glad you like it!

Have written a much improved version which I'll post as soon as I can get to it again, plus added most of the tween types from the AS library.

Should also mention that all the equations come from this clever chap Robert Penner:

http://www.robertpenner.com/easing/
I'm wondering whether to make the addTween function more like the AS version, which takes a dictionary of parameters, but I'm not sure I like the syntax:

addTween( myObject, { "position": newPosition, "tweenType":"EaseInOutSin", "time":1.0 } )

however perhaps it could be done with arbitrary keywords in any order:

`addTween( myObject, position=newPosition, time=50, tweenType=EASE_OUT_QUAD, rotation=newRotation )`

Also perhaps just combine the function and property tweens into one Tween class, and use try: except: to see whether its a property or a function we're dealing with. Finally, it should also be able to detect the initial value you're tweening from without needing to be told ( either by reading the property initially or trying to run the "get" version of the function.)

what do you think?

bharling

01-02-2009 13:09:52

right, I re-wrote it to be more like the AS original and accept a variety of arguments without worrying too much.

so to use it now, its just:

import pyTweener.Tweener as Tweener

...

tweener = Tweener()

...

tweener.addTween( myRocket, setThrust=ogre.Vector3(0,200,0), tweenTime=2.0, tweenType=tweener.IN_OUT_CUBIC, onCompleteFunction=self.rocketLaunched, scale=2.0 )

activeTweens = tweener.getTweensAffectingObject( myobj )

for t in activeTweens:

t.pause()

...

tweener.update( timeSinceLastFrame )

here it is, with more of Penner's easing equations added:

`import math`

class Tweener:

def __init__(self):

self.currentTweens = []

self.defaultTweenType = self.IN_OUT_QUAD

self.defaultDuration = 1.0

def OUT_EXPO(self, t, b, c, d ):

return b+c if (t==d) else c * (-math.pow(2, -10 * t/d) + 1) + b;

def LINEAR (self, t, b, c, d):

return c*t/d + b

def IN_QUAD (self, t, b, c, d):

t/=d

return c*(t)*t + b

def OUT_QUAD (self, t, b, c, d):

t/=d

return -c *(t)*(t-2) + b

def IN_OUT_QUAD( self, t, b, c, d ):

t/=d/2

if ((t) < 1): return c/2*t*t + b

t-=1

return -c/2 * ((t)*(t-2) - 1) + b

def OUT_IN_QUAD( self, t, b, c, d ):

if (t < d/2):

return self.OUT_QUAD (t*2, b, c/2, d)

return self.IN_QUAD((t*2)-d, b+c/2, c/2)

def IN_CUBIC(self, t, b, c, d):

t/=d

return c*(t)*t*t + b

def OUT_CUBIC(self, t, b, c, d):

t=t/d-1

return c*((t)*t*t + 1) + b

def IN_OUT_CUBIC( self, t, b, c, d):

t/=d/2

if ((t) < 1):

return c/2*t*t*t + b

t-=2

return c/2*((t)*t*t + 2) + b

def OUT_IN_CUBIC( self, t, b, c, d ):

if (t < d/2): return self.OUT_CUBIC (t*2, b, c/2, d)

return self.IN_CUBIC((t*2)-d, b+c/2, c/2, d)

def IN_QUART( self, t, b, c, d):

t/=d

return c*(t)*t*t*t + b

def OUT_QUART( self, t, b, c, d):

t=t/d-1

return -c * ((t)*t*t*t - 1) + b

def IN_OUT_QUART( self, t, b, c, d):

t/=d/2

if (t < 1):

return c/2*t*t*t*t + b

t-=2

return -c/2 * ((t)*t*t*t - 2) + b

def OUT_ELASTIC(self, t, b, c, d): # Not working :(

if (t==0):

return b

t/=d

if t==1:

return b+c

p = period = d*.3

a = amplitude = 1.0

if a < abs(c):

a = c

s = p/4

else:

s = p/(2*math.pi) * math.asin (c/a)

return (a*math.pow(2,-10*t) * math.sin( (t*d-s)*(2*math.PI)/p ) + c + b)

def hasTweens(self):

return len(self.currentTweens) > 0

def addTween(self, obj, **kwargs):

""" addTween( object, **kwargs) -> tweenObject or False

kwargs should include tweenTime and tweenType and

at least one property or function of the object

with the change value.eg:

tweener.addTween( myRocket, throttle=50, setThrust=400, tweenTime=5.0, tweenType=tweener.OUT_QUAD )"""

if kwargs.has_key("tweenTime"):

t_time = kwargs.pop("tweenTime")

else: t_time = self.defaultDuration

if kwargs.has_key("tweenType"):

t_type = kwargs.pop("tweenType")

else: t_type = self.defaultTweenType

if kwargs.has_key("onCompleteFunction"):

t_completeFunc = kwargs.pop("onCompleteFunction")

else: t_completeFunc = None

if kwargs.has_key("tweenDelay"):

t_delay = kwargs.pop("tweenDelay")

else: t_delay = 0

tw = Tween( obj, t_time, t_type, t_completeFunc, t_delay, **kwargs )

if tw:

self.currentTweens.append( tw )

return tw

def removeTween( tweenObj ):

if self.currentTweens.contains( tweenObj ):

tweenObj.complete = True

#self.currentTweens.remove( tweenObj )

def getTweensAffectingObject( self, obj ):

tweens = []

for t in self.currentTweens:

if t.target is obj:

tweens.append(t)

return tweens

def removeTweeningFrom( self, obj ):

for t in self.currentTweens:

if t.target is obj:

t.complete = True

def update(self, timeSinceLastFrame):

for t in self.currentTweens:

if not t.complete:

t.update( timeSinceLastFrame )

else:

self.currentTweens.remove(t)

class Tween:

def __init__(self, obj, duration, tweenType, completeFunction, delay, **kwargs):

self.duration = duration

self.delay = delay

self.target = obj

self.tween = tweenType

self.tweenables = kwargs

self.delta = 0

self.completeFunction = completeFunction

self.complete = False

self.tProps = []

self.tFuncs = []

self.paused = self.delay > 0

self.decodeArguments()

def decodeArguments(self):

if len(self.tweenables) == 0:

# nothing to do

print "TWEEN ERROR: No Tweenable properties or functions defined"

self.complete = True

return

for k, v in self.tweenables.items():

# check that its compatible

if not hasattr( self.target, k):

print "TWEEN ERROR: " + str(self.target) + " has no function " + k

self.complete = True

break

prop = func = False

startVal = 0

change = v

try:

startVal = self.target.__dict__[k]

prop = k

except:

func = getattr( self.target, k)

funcName = k

if func:

try:

getFunc = getattr(self.target, funcName.replace("set", "get") )

print "Found getter function"

startVal = getFunc()

except:

# no start value, assume its 0

# but make sure the start and change

# dataTypes match :)

startVal = change * 0

self.tFuncs.append( [ func, startVal, change ] )

if prop:

self.tProps.append( [prop, startVal, change])

def pause( self, numSeconds=-1 ):

self.paused = True

self.delay = numSeconds

def resume( self ):

if self.paused:

self.paused=False

def update(self, ptime):

if self.paused:

if self.delay > 0:

self.delay = max( 0, self.delay - ptime )

if self.delay == 0:

self.paused = False

self.delay = -1

return

self.delta = min(self.delta + ptime, self.duration)

if self.delta == self.duration:

self.complete = True

if self.completeFunction:

self.completeFunction()

return

for prop, start, change in self.tProps:

self.target.__dict__[prop] = self.tween( self.delta, start, change, self.duration )

for func, start, change in self.tFuncs:

func( self.tween( self.delta, start, change, self.duration ) )

def Remove(self):

"""Disables and removes this tween

without calling the complete function"""

self.complete = True

class TweenTestObject:

def __init__(self):

self.pos = 20

self.rot = 50

def setRotation(self, rot):

self.rot = rot

def getRotation(self):

return self.rot

def complete(self):

print "hello im done with tweening"

if __name__=="__main__":

import time

T = Tweener()

tst = TweenTestObject()

T.addTween( tst, setRotation=523.0, tweenTime=2, tweenType=T.OUT_EXPO, pos=-200, tweenDelay=0.4 )

s = time.clock()

while T.hasTweens():

tm = time.clock()

d = tm - s

s = tm

T.update( d )

print tst.getRotation(), tst.pos

time.sleep(0.006)

Be warned the error checking is abysmal, I could really do with some help on that if anyone would like to!

Also its not tested very well, so might go wrong at times.

Guess the license should be the same as for the original

caurina tweener which is MIT

I hope to wiki it later when its more complete

Danaugrs

01-02-2009 14:09:57

I'm not really fond of the dictionary syntax too, I prefer the second

Combining the property and function into one class is a good idea.

I'd really like to help, but after my classes start I will have little if any time to code

Guess the license should be the same as for the original caurina tweener which is MIT

It is good to maintain the original license, especially such a nice one

So, how can I help? hehe

bharling

03-02-2009 13:15:50

I placed a further updated version on the wiki while ogre3d was down. This new version allows tweens to be modified while they are running via a 'Tweenable' class.

see here:

http://wiki.python-ogre.org/index.php/CodeSnippits_pyTweener
Have also tidied it all up a bit, and made a stab at some documentation. I'll only update the wiki version from now on as this is definitely the best so far

zorrito

02-05-2009 18:45:08

You should contact

zisforzeh so this is added to the list of ports in the tweener project main page =)

Good work

bharling

04-05-2009 11:55:31

Cool,

I managed to find his email eventually and have notified him

thanks!

kyathir

10-05-2009 22:03:48

It looks useful =)

I'm sure that I'll use it many times in the future ^^