Lingo: tinyTween parentScript

Table of contents





tinyTween parentScript


This Parentscript tweens objects timebased.
There are two flavours: Passive and Active. In passive mode you initialize the script and call an update command from within a behaviour.
The active mode needs a target sprite, initializes and takes care of the tween by itself, using the actorlist/stepframe. When the tween is done, it destroys itself.

MW

version history

1.3.0 - fixed bug on passive mode #start:0
1.2.0 - added passive mode
1.1.4 - added bounce en elastic tweens, modified destroy function
1.1.3 - fixed blend bug in shortcuts, added #jojo, added #repeat
1.1.2 - fixed rect bug in shortcuts
1.1.1 - added shorcuts


Passive mode

tinyTween object

tinyTween object
n = script("tinyTween").new(propertyList)


tween properties in Passive mode


  • start (int/float/point/vector/rect)
  • end (int/float/point/vector/rect)

  • duration (int: tweenDuration in milliseconds)
  • delay (int: delay in milliseconds)
  • repeat (int: times a tween is repeated, use 0 or "inf" for infinite repeat)
  • jojo (int: 1/0, makes the tween go back-and-forth)
  • tweenmode (string: see tweenModes)


Example

tinyTween in a behaviour
property pTween

on beginSprite me
  pTween = script("tinyTween").new([#start:point(100,100), #end:point(600,200), #duration:4000, #tweenMode:"bounce", #jojo:1, #repeat:"inf"])
end

on exitFrame me
  sprite(me.spritenum).loc = pTween.update()  
end


Active mode

tinyTween object

tinyTween object
n = script("tinyTween").new(spriteObject, propertyList, stringActionOnTweenComplete)


Basic tween properties in Active Mode

The following properties are endvalues of the tween, the startvalues are based on the current properties of the sprite.

  • blend (int)
  • loc (point)
  • locH (int)
  • locV (int)
  • rect (rect/list)
  • rotation (int)

  • duration (int: tweenDuration in milliseconds)
  • delay (int: delay in milliseconds)
  • repeat (int: times a tween is repeated, use 0 or "inf" for infinite repeat)
  • jojo (int: 1/0, makes the tween go back-and-forth)
  • tweenmode (string: see tweenModes)

  • stringActionOnTweenComplete (string, calls the 'do' command in lingo)

So if sprite "wokkie" on the stage has a blend of 100, then the following code will blend the sprite in 1 second from 100 to 0.

tinyTween basic sample
n = script("tinyTween").new(sprite("wokkie"), [#blend:0, #duration:1000])


Advanced tween properties in Active mode

The advanced properties have start- and endvalues.

  • startBlend (int)
  • endBlend (int)
  • startLoc (point)
  • endLoc (point)
  • startLocH (int/float)
  • endLocH (int/float)
  • startLocV (int/float)
  • endLocV (int/float)
  • startWidth (int/float)
  • endWidth (int/float)
  • startHeight (int/float)
  • endHeight (int/float)
  • startRect (rectangle/list)

For every property (Example 'rotation') you set a startRotation and a endRotation. So:
code sample
n = script("tinyTween").new(sprite(1), [#startRotation:0, #endRotation:360,  #duration:2000, #tweenMode:"easeInOutBack", #delay:1000, #repeat:4, #jojo:1])


special arguments in Active mode

The argument stringActionOnTweenComplete has the following states:

  • void of omitted: no action
  • string with handlername: calls a 'do' command

This code makes sprite 1 rotate four times and therefore calls four times the handler "doTheWokkie".
code sample
n = script("tinyTween").new(sprite(1), [#startRotation:0, #endRotation:360,  #duration:2000, #tweenMode:"easeInOutBack", #delay:1000, #repeat:4, #jojo:1], "doTheWokkie")



tweenModes

The tweenmodes are insired by these (external link) tweens.

linear
  • linear
sine
  • easeInSine
  • easeOutSine
  • easeInOutSine
  • easeOutInSine
Quad
  • easeInQuad
  • easeOutQuad
  • easeInOutQuad
  • easeOutInQuad
Back
  • easeInBack
  • easeOutBack
  • easeInOutBack
  • easeOutInBack
Quart
  • easeInQuart
  • easeOutQuart
  • easeInOutQuart
  • easeOutInQuart
Special
  • bounce
  • superBounce
  • elastic
  • superElastic

tinyTween source

Copy this code in a parensScript member and call it "tinyTween"

tinyTween source
--@--------------------------------
--@ tinyTween by MW @ Kiss the Frog 2010/2011
--@
--@
--@ timebased tweenScript v 1.3.0 beta
--@ 
--@ active mode sample usage:
--@ n = script("tinyTween").new(spriteObject, propertyList, stringActionOnTweenComplete)
--@ n = script("tinyTween").new(sprite(1), [#startRotation:0, #endRotation:360,  #duration:2000, #tweenMode:"easeInOutBack", #jojo:1, #repeat:0], "onTweenComplete")
--@ 
--@ passive mode sample usage:
--@ 
--@ --Behaviour script
--@ property pTween
--@ 
--@ on beginSprite me
--@   pTween = script("tinyTween").new([#start:point(100,100), #end:point(600,200), #duration:4000, #tweenMode:"elastic", #jojo:1, #repeat:0])
--@ end
--@ 
--@ on exitFrame me
--@   sprite(me.spritenum).loc = pTween.update()  
--@ end
--@ 
--@---------------------------------

property pSprite    --SpriteObject

--reserved
property pStartTime --Integer (milliseconds)
property pEnded     --Boolean
property pPassiveMode

--modifiers
property pTweenmode --String
property pAction    --String ('do' command)
property pDuration  --Integer (milliseconds)
property pDelay     --Integer (milliseconds)
property pRepeat    --Integer
property pJojo      --Integer (0/1)
property pInfinite
property props      --proplist



--bezier
property ppath      --propList

--sin
property pBounciness

-------------------------
-- PUBLIC ---------------
-------------------------

on new(me,_sprite,prop, _action)
  
  --init
  pAction     = _action
  ppath       = [:]
  pBounciness = 0
  pPassiveMode= 0
  
  if ilk(_sprite) = #propList then --we are going for passive mode!
    ---------------
    --PASSIVE
    ---------------
    
    prop = _sprite.duplicate()
    --setup the tween
    setupTinyTween(me,prop)
  else
    ---------------
    --ACTIVE
    ---------------
    
    pSprite     = _sprite  
    --setup the tween
    setupTinyTween(me,prop)
    
    --add to actor
    (the actorList).add(me)
  end if
  
  return me
end


on destroy(me)
  --delete instance
  n = (the actorList).getPos(me)
  if n > 0 then (the actorList).deleteAt(n)
end




-------------------------
-- PRIVATE --------------
-------------------------

on setupTinyTween(me,prop)
  if ilk(prop) = #propList then
    
    --Check if we're in passive mode
    if voidP(prop.getAprop(#start))= false and voidP(prop.getAprop(#end)) = false then
      
      -----------------------
      --PASSIVE MODE
      -----------------------
      
      --defaults
      
      pPassiveMode = 1
      pTweenmode   = "easeInSine"
      pDuration    = 1000
      pDelay       = 0
      pRepeat      = 1
      pJojo        = 0
      pInfinite    = false
      props        = [:] 
      
      if not voidP(prop["tweenMode"]) then pTweenMode = prop["tweenMode"]
      if not voidP(prop["duration"]) then pDuration = prop["duration"]
      if not voidP(prop["jojo"]) then pJojo = prop["jojo"]
      if not voidP(prop["repeat"]) then pRepeat = prop["repeat"]
      if not voidP(prop["delay"]) then pDelay = prop["delay"]
      
      
      if not voidP(prop["start"]) then 
        props.addProp(#start, prop["start"] )
        props.addProp(#end, prop["end"] )
        props.addProp(#distance, (prop["start"] - prop["end"]))
      end if
      
      
      --[Some checks]----------------------------------
      --check for infinite tween
      if pRepeat = 0 or pRepeat = "inf" then 
        pRepeat = 99 --just a number
        pInfinite = true
      end if
      
      --Check for jojo. If true, the tween will be devided in 'back and Forth' in the given tweentime
      if pJojo = 1 then
        pRepeat = pRepeat * 2
        pDuration = pDuration/2.0
      end if
      
      tinyTween(me)
    else
      
      -----------------------
      --ACTIVE MODE
      -----------------------
      
      --defaults
      pTweenmode = "easeInSine"
      pDuration  = 1000
      pDelay     = 0
      pRepeat    = 1
      pJojo      = 0
      pInfinite  = false
      props      = [:] 
      
      --[general]---------------------------------------
      if not voidP(prop["duration"]) then pDuration = prop["duration"]
      if not voidP(prop["delay"]) then pDelay = prop["delay"]
      if not voidP(prop["tweenMode"]) then pTweenmode = prop["tweenMode"]
      if not voidP(prop["jojo"]) then pJojo = prop["jojo"]
      if not voidP(prop["repeat"]) then pRepeat = prop["repeat"]
      
      
      --[Some checks]----------------------------------
      --check for infinite tween
      if pRepeat = 0 or pRepeat = "inf" then 
        pRepeat = 99 --just a number
        pInfinite = true
      end if
      
      --Check for jojo. If true, the tween will be devided in 'back and Forth' in the given tweentime
      if pJojo = 1 then
        pRepeat = pRepeat * 2
        pDuration = pDuration/2.0
      end if
      
      
      --[ShortCuts]-------------------------------------
      --Uses the pSprite properties as start-values.
      
      if not voidP(prop["rect"]) then 
        props.addProp(#left,[#startLeft:pSprite.rect[1], #endLeft:prop["rect"][1],#distanceLeft:pSprite.rect[1] - prop["rect"][1]] )
        props.addProp(#top,[#startTop:pSprite.rect[2], #endTop:prop["rect"][2],#distanceTop:pSprite.rect[2] - prop["rect"][2]] )
        props.addProp(#right,[#startRight:pSprite.rect[3], #endRight:prop["rect"][3],#distanceRight:pSprite.rect[3] - prop["rect"][3]] )
        props.addProp(#bottom,[#startBottom:pSprite.rect[4], #endbottom:prop["rect"][4],#distanceBottom:pSprite.rect[4] - prop["rect"][4]] )
      end if
      
      
      
      if not voidP(prop["loc"]) then 
        props.addProp(#locH,[#startLocH:pSprite.loc[1], #endLocH:prop["loc"][1],#distanceH:pSprite.loc[1] - prop["loc"][1]] )
        props.addProp(#locV,[#startLocV:pSprite.loc[2], #endLocV:prop["loc"][2],#distanceV:pSprite.loc[2] - prop["loc"][2]] )
      end if
      
      if not voidP(prop["locH"]) then props.addProp(#locH,[#startLocH:pSprite.locH, #endLocH:prop["locH"],#distanceH:pSprite.locH - prop["LocH"]] )
      if not voidP(prop["locV"]) then props.addProp(#locV,[#startLocV:pSprite.locV, #endLocV:prop["locV"],#distanceV:pSprite.locV - prop["locV"]] )
      if not voidP(prop["width"]) then props.addProp(#width,[#startWidth:pSprite.width, #endWidth:prop["width"],#distanceWidth:pSprite.width - prop["width"]] )
      if not voidP(prop["height"]) then props.addProp(#height,[#startHeight:pSprite.height, #endHeight:prop["height"],#distanceHeight:pSprite.height - prop["height"]] )
      if not voidP(prop["blend"]) then props.addProp(#blend,[#startBlend:pSprite.blend, #endBlend:prop["blend"],#distanceBlend:pSprite.blend - prop["blend"]] )
      if not voidP(prop["rotation"]) then props.addProp(#rotation,[#startRotation:pSprite.rotation, #endRotation:prop["rotation"],#distanceRotation:pSprite.rotation - prop["rotation"]] )
      
      if not voidP(prop["left"]) then props.addProp(#left,[#left:pSprite.left, #endLeft:prop["left"],#distanceLeft:pSprite.left - prop["left"]] )
      if not voidP(prop["top"])  then props.addProp(#top,[#top:pSprite.top, #endTop:prop["top"],#distanceTop:pSprite.top - prop["top"]] )
      if not voidP(prop["right"]) then props.addProp(#right,[#right:pSprite.right, #endRight:prop["right"],#distanceRight:pSprite.right - prop["right"]]  )
      if not voidP(prop["bottom"])then props.addProp(#bottom,[#bottom:pSprite.bottom, #endBottom:prop["bottom"],#distanceBottom:pSprite.bottom - prop["bottom"]])
      
      
      --[The Whole nine Yards]---------------------------
      --Needs startProperty and EndProperty to work.
      
      if not voidP(prop["startLocH"]) and not voidP(prop["endLocH"]) then props.addProp(#locH,[#startLocH:prop["startLocH"], #endLocH:prop["endLocH"],#distanceH:prop["startLocH"] - prop["endLocH"]] )
      if not voidP(prop["startLocV"]) and not voidP(prop["endLocV"]) then props.addProp(#locV,[#startLocV:prop["startLocV"], #endLocV:prop["endLocV"],#distanceV:prop["startLocV"] - prop["endLocV"]] )
      if not voidP(prop["startWidth"]) and not voidP(prop["endWidth"]) then props.addProp(#width,[#startWidth:prop["startWidth"], #endWidth:prop["endWidth"],#distanceWidth:prop["startWidth"] - prop["endWidth"]] )
      if not voidP(prop["startHeight"]) and not voidP(prop["endHeight"]) then props.addProp(#height,[#startHeight:prop["startHeight"], #endHeight:prop["endHeight"],#distanceHeight:prop["startHeight"] - prop["endHeight"]] )
      if not voidP(prop["startBlend"]) and not voidP(prop["endBlend"]) then props.addProp(#blend,[#startBlend:prop["startBlend"], #endBlend:prop["endBlend"],#distanceBlend:prop["startBlend"] - prop["endBlend"]] )
      if not voidP(prop["startRotation"]) and not voidP(prop["endRotation"]) then props.addProp(#Rotation,[#startRotation:prop["startRotation"], #endRotation:prop["endRotation"],#distanceBlend:prop["startRotation"] - prop["endRotation"]] )
      
      if not voidP(prop["startLeft"]) and not voidP(prop["endLeft"]) then  props.addProp(#left,[#startLeft:prop["startLeft"], #endLeft:prop["endLeft"],#distanceLeft:prop["startLeft"] - prop["endLeft"]] )
      if not voidP(prop["startTop"]) and not voidP(prop["endTop"]) then props.addProp(#top,[#startTop:prop["startTop"], #endTop:prop["endTop"],#distanceTop:prop["startTop"] - prop["endTop"]] )
      if not voidP(prop["startRight"]) and not voidP(prop["endRight"]) then props.addProp(#right,[#startRight:prop["startRight"], #endRight:prop["endRight"],#distanceRight:prop["startRight"] - prop["endRight"]]  )
      if not voidP(prop["startBottom"]) and not voidP(prop["endBottom"]) then props.addProp(#bottom,[#startBottom:prop["startBottom"], #endBottom:prop["endBottom"],#distanceBottom:prop["startBottom"] - prop["endBottom"]])
      
      
      
      --multiDimensional
      if not voidP(prop["startRect"]) and not voidP(prop["endRect"]) then 
        props.addProp(#left,[#startLeft:prop["startRect"][1], #endLeft:prop["endRect"][1],#distanceLeft:prop["startRect"][1] - prop["endRect"][1]] )
        props.addProp(#top,[#startTop:prop["startRect"][2], #endTop:prop["endRect"][2],#distanceTop:prop["startRect"][2] - prop["endRect"][2]] )
        props.addProp(#right,[#startRight:prop["startRect"][3], #endRight:prop["endRect"][3],#distanceRight:prop["startRect"][3] - prop["endRect"][3]] )
        props.addProp(#bottom,[#startBottom:prop["startRect"][4], #endBottom:prop["endRect"][4],#distanceBottom:prop["startRect"][4] - prop["endRect"][4]] )
      end if
      
      if not voidP(prop["startLoc"]) and not voidP(prop["endLoc"]) then 
        props.addProp(#locH,[#startLocH:prop["startLoc"][1], #endLocH:prop["endLoc"][1],#distanceH:prop["startLoc"][1] - prop["endLoc"][1]] )
        props.addProp(#locV,[#startLocV:prop["startLoc"][2], #endLocV:prop["endLoc"][2],#distanceV:prop["startLoc"][2] - prop["endLoc"][2]] )
      end if
      
      
      tinyTween(me)
    end if
    
  end if
end


on tinyTween(me,inv)
  
  
  
  if pPassiveMode = 1 then
    
    if inv = true then 
      repeat with i = 1 to props.count
        s = props.end
        e = props.start
        props.start = s
        props.end = e
        props.distance = s - e
      end repeat
    end if
    
    
  else
    
    if inv = true then 
      repeat with i = 1 to props.count
        s = props[i][2]
        e = props[i][1]
        props[i][1] = s
        props[i][2] = e
        props[i][3] = s - e
      end repeat
    end if
    
    
    repeat with i = 1 to props.count
      do "pSprite."&string(props.getPropAt(i))&&" = props[i][1]" --start
    end repeat
  end if
  
  pStartTime  = the milliseconds
  pEnded      = false  
  
  setTween(me)
  
end


on setTween(me)
  case pTweenmode of
      --linear  
    "linear"       :  SetupBezier(me, point(0,0),point(0,0),point(100,100),point(100,100))  
      
      --sine
    "easeInSine"   :  SetupBezier(me, point(0,0),point(10,0),point(100,100),point(100,100))  
    "easeOutSine"  :  SetupBezier(me, point(0,0),point(0,0),point(90,100),point(100,100))  
    "easeInOutSine":  SetupBezier(me, point(0,0),point(10,0),point(90,100),point(100,100))  
    "easeOutInSine":  SetupBezier(me, point(0,0),point(60,50),point(40,50),point(100,100))  
      
      --Quad
    "easeInQuad"   :  SetupBezier(me, point(0,0),point(20,0),point(100,100),point(100,100))  
    "easeOutQuad"  :  SetupBezier(me, point(0,0),point(0,0),point(80,100),point(100,100))  
    "easeInOutQuad":  SetupBezier(me, point(0,0),point(20,0),point(80,100),point(100,100))  
    "easeOutInQuad":  SetupBezier(me, point(0,0),point(70,50),point(30,50),point(100,100))  
      
      --Back
    "easeInBack"   :  SetupBezier(me, point(0,0),point(5,0),point(-50,100),point(100,100))  
    "easeOutBack"  :  SetupBezier(me, point(0,0),point(150,0),point(95,100),point(100,100))  
    "easeInOutBack":  SetupBezier(me, point(0,0),point(-30,0),point(130,100),point(100,100))
    "easeOutInBack":  SetupBezier(me, point(0,0),point(130,100),point(-30,0),point(100,100))
      
      --Quart
    "easeInQuart"   : SetupBezier(me, point(0,0),point(50,0),point(100,100),point(100,100))  
    "easeOutQuart"  : SetupBezier(me, point(0,0),point(0,0),point(50,100),point(100,100))  
    "easeInOutQuart": SetupBezier(me, point(0,0),point(50,0),point(50,100),point(100,100))  
    "easeOutInQuart": SetupBezier(me, point(0,0),point(100,50),point(0,50),point(100,100))  
      
      --Special
    "bounce"        : SetupBounceBezier(me, 100)
    "superBounce"   : SetupBounceBezier(me, 66)
    "elastic"       : SetupBounceBezier(me, 100)
    "superElastic"  : SetupBounceBezier(me, 66)
      
    otherwise
      --linear
      SetupBezier(me, point(0,0),point(0,0),point(100,100),point(100,100))  
  end case
end

on SetupBezier(me, var1,var2,var3,var4)
  ppath = [#p0:var1,#p1:var2,#p2:var3,#p3:var4]
  setaProp pPath, #dc, 3 * (pPath.p1 - pPath.p0)
  setaProp pPath, #db, 3 * (pPath.p2 - pPath.p1) - pPath.dc
  setaProp pPath, #da, pPath.p3 - pPath.p0 - pPath.dc - pPath.db
end

on SetupBounceBezier(me,amount)
  pBounciness = amount 
end


on GetPosition(me, timetoget)
  
  if pTweenmode contains "bounce" or pTweenmode contains "elastic"  then
    
    n = getBouncePosition(me, timetoget)  
    
    if pTweenMode contains "elastic" then
      return [100 - ((100 - timetoget) * n),0]
    else
      return [100 - ((100 - timetoget) * abs(n)),0]
    end if
    
  else  
    
    
    if ppath = [:] then return -1
    if timetoget > 100 then timetoget = 100
    if timetoget < 0 then timetoget = 0
    if timetoget = 100 then
      return  ppath.p3
    else
      vT1 = float (timetoget )/ 100.0
      vT2 = vT1 * vT1
      vT3 = vT2 * vT1
      vNewPosition = pPath.p0
      vModPoint = pPath.dc * vT1
      vNewPosition = vNewPosition + vModPoint
      vModPoint = pPath.db * vT2
      vNewPosition = vNewPosition + vModPoint
      vModPoint = pPath.da * vT3
      vNewPosition = vNewPosition + vModPoint
      return vNewPosition
    end if
  end if
  
  
end


on getBouncePosition(me, timetoget)
  t = ((0.5 * pi) + (((100)/((2*pi)*pBounciness)  * timeToGet )))
  n = sin(t)
  if t > pi then n = n / ((timetoget * 0.2)*pBounciness/100.0)
  
  return n
end


--update

on update(me)
  _time = the milliseconds - pStartTime - pDelay
  -- put _time
  
  if _time > pDuration then
    
    -- n =  props.duplicate()
    
    if pRepeat > 0 then
      if pRepeat > 1 then  tinyTween(me, pJojo)
      if pInfinite = false then pRepeat = pRepeat - 1
    end if
    if pJojo = 1 then 
      return props.start  
    else
      return props.end 
    end if
    
  else if _time > 0 then
    _timeToGet  = _time/(pDuration * 1.0) * 100
    _tween      =GetPosition(me, _timetoget)[1]
    
    return (props.start - ((props.distance/100.0) * _tween))
    
  else
    return props.start
  end if
  
  
  
end



--Loop

on stepframe(me)
     
  
  --check is tween is still active
  if pEnded = false then
    _time = the milliseconds - pStartTime - pDelay
    if _time > pDuration then
      
      --set all active properties to endProp
      repeat with i = 1 to props.count
        do "pSprite."&string(props.getPropAt(i))&&" = props[i][2]"
      end repeat
      
      pEnded = true
      pBezier = void
      
      if pRepeat > 0 then
        
        if pRepeat > 1 then  tinyTween(me, pJojo)
        if pInfinite = false then pRepeat = pRepeat - 1
        if not voidP(pAction)then do pAction
        
      else
        --Tween ends, destroy!
        destroy(me)
        if not voidP(pAction)then do pAction
        
      end if
      
    else if _time > 0 then
      _timeToGet  = _time/(pDuration * 1.0) * 100
      _tween      =GetPosition(me, _timetoget)[1]
      
      repeat with i = 1 to props.count
        
        --Check blend
        if string(props.getPropAt(i)) contains "blend" then
          n = props[i][1] - ((props[i][3]/100.0) * _tween)
          --Fix blends
          if n > 100 then n = 100
          if n < 0 then n = 0
          
          pSprite.blend = n
        else
          do "pSprite."&string(props.getPropAt(i))&&" = props[i][1] - ((props[i][3]/100.0) * _tween)"
        end if
        
      end repeat
      
    end if
  else
    destroy(me)
  end if
end