utils/tweens.bs

' @module BGE
namespace BGE.Tweens
  ' ******************************************************
  ' Copyright Steven Kean 2010-2015
  ' All Rights Reserved.
  ' ******************************************************
  function CreateTweenObject(start_data as object, dest_data as object, duration as integer, tween as string) as object
    tween_data = {
      start: {},
      current: {},
      dest: {},
      duration: duration,
      timer: invalid,
      tween: tween
    }
    for each key in start_data
      tween_data.start[key] = start_data[key]
      tween_data.current[key] = start_data[key]
    end for
    for each key in dest_data
      tween_data.dest[key] = dest_data[key]
    end for
    tween_data.timer = new BGE.GameTimer()

    return tween_data
  end function

  function GetTweenObjectPercentState(tween_object as object) as float
    key = invalid
    largest_start_dest_difference = 0
    for each k in tween_object.start
      start_dest_difference = (tween_object.start[k] - tween_object.dest[k])
      if start_dest_difference > largest_start_dest_difference
        largest_start_dest_difference = start_dest_difference
        key = k
      end if
    end for

    if (tween_object.start[key] - tween_object.dest[key]) = 0
      return 1.0
    end if

    if key = invalid
      return 0
    end if

    return (tween_object.start[key] - tween_object.current[key]) / (tween_object.start[key] - tween_object.dest[key])
  end function

  function HandleTween(tween_data as object) as boolean

    ' Example
    ' m.movement_data = {
    '     start: {x: x, y: y}
    '     current: {x: x, y: y}
    '     dest: {x: x, y: y}
    '     duration: 90
    '     timer: CreateObject("roTimespan")
    '     tween: "LinearTween"
    ' }


    tween = "LinearTween"
    if tween_data.DoesExist("tween")
      tween = tween_data.tween
    end if

    current_time = tween_data.timer.TotalMilliseconds()
    for each key in tween_data.start
      tween_data.current[key] = m.tweens[tween](tween_data.start[key], tween_data.dest[key], current_time, tween_data.duration)
    end for

    return current_time >= tween_data.duration

  end function

  function ChangeTweenDest(tween_data as object, dest_data as object)
    tween_data.timer.Mark()
    for each key in dest_data
      tween_data.start[key] = tween_data.current[key]
      tween_data.dest[key] = dest_data[key]
    end for
  end function

  function GetTweens() as object
    if m.tweens = invalid
      m.tweens = {
        LinearTween: LinearTween,
        QuadraticTween: QuadraticTween,
        QuadraticEaseIn: QuadraticEaseIn,
        QuadraticEaseOut: QuadraticEaseOut,
        QuadraticEaseInOut: QuadraticEaseInOut,
        QuadraticEaseOutIn: QuadraticEaseOutIn,
        SquareTween: SquareTween,
        SquareEaseIn: SquareEaseIn,
        SquareEaseOut: SquareEaseOut,
        SquareEaseInOut: SquareEaseInOut,
        SquareEaseOutIn: SquareEaseOutIn,
        CubicTween: CubicTween,
        CubicEaseIn: CubicEaseIn,
        CubicEaseOut: CubicEaseOut,
        CubicEaseInOut: CubicEaseInOut,
        CubicEaseOutIn: CubicEaseOutIn,
        QuarticTween: QuarticTween,
        QuarticEaseIn: QuarticEaseIn,
        QuarticEaseOut: QuarticEaseOut,
        QuarticEaseInOut: QuarticEaseInOut,
        QuarticEaseOutIn: QuarticEaseOutIn,
        QuinticTween: QuinticTween,
        QuinticEaseIn: QuinticEaseIn,
        QuinticEaseOut: QuinticEaseOut,
        QuinticEaseInOut: QuinticEaseInOut,
        QuinticEaseOutIn: QuinticEaseOutIn,
        SinusoidalTween: SinusoidalTween,
        SinusoidalEaseIn: SinusoidalEaseIn,
        SinusoidalEaseOut: SinusoidalEaseOut,
        SinusoidalEaseInOut: SinusoidalEaseInOut,
        SinusoidalEaseOutIn: SinusoidalEaseOutIn,
        ExponentialTween: ExponentialTween,
        ExponentialEaseIn: ExponentialEaseIn,
        ExponentialEaseOut: ExponentialEaseOut,
        ExponentialEaseInOut: ExponentialEaseInOut,
        ExponentialEaseOutIn: ExponentialEaseOutIn,
        CircularTween: CircularTween,
        CircularEaseIn: CircularEaseIn,
        CircularEaseOut: CircularEaseOut,
        CircularEaseInOut: CircularEaseInOut,
        CircularEaseOutIn: CircularEaseOutIn,
        ElasticTween: ElasticTween,
        ElasticEaseIn: ElasticEaseIn,
        ElasticEaseOut: ElasticEaseOut,
        ElasticEaseInOut: ElasticEaseInOut,
        ElasticEaseOutIn: ElasticEaseOutIn,
        OvershootTween: OvershootTween,
        OvershootEaseIn: OvershootEaseIn,
        OvershootEaseOut: OvershootEaseOut,
        OvershootEaseInOut: OvershootEaseInOut,
        OvershootEaseOutIn: OvershootEaseOutIn,
        BounceTween: BounceTween,
        BounceEaseIn: BounceEaseIn,
        BounceEaseOut: BounceEaseOut,
        BounceEaseInOut: BounceEaseInOut,
        BounceEaseOutIn: BounceEaseOutIn
      }
    end if
    return m.tweens
  end function

  function LinearTween(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*t/d + b
    time = currentTime / duration
    return change * time + start
  end function

  ' ****************
  ' Quadratic
  ' ****************
  function QuadraticTween(start as float, finish as float, currentTime as float, duration as float) as float
    return QuadraticEaseInOut(start, finish, currentTime, duration)
  end function

  function QuadraticEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*(t/=d)*t + b
    time = currentTime / duration
    return change * time * time + start
  end function

  function QuadraticEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' -c *(t/=d)*(t-2) + b
    time = currentTime / duration
    return -change * time * (time - 2) + start
  end function

  function QuadraticEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if ((t/=d/2) < 1) return c/2*t*t + b;
    ' return -c/2 * ((--t)*(t-2) - 1) + b;
    time = currentTime / (duration / 2)
    if time < 1
      return change / 2 * time * time + start
    else
      time = time - 1
      return -change / 2 * (time * (time - 2) - 1) + start
    end if
  end function

  function QuadraticEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return QuadraticEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return QuadraticEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Square
  ' ****************
  function SquareTween(start as float, finish as float, currentTime as float, duration as float) as float
    return SquareEaseInOut(start, finish, currentTime, duration)
  end function

  function SquareEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*(t/=d)*t*t*t + b
    time = currentTime / duration
    return change * time * time + start
  end function

  function SquareEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' -c * ((t=t/d-1)*t*t*t - 1) + b
    time = (currentTime / duration) - 1
    return -change * (time * time - 1) + start
  end function

  function SquareEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
    ' return -c/2 * ((t-=2)*t*t*t - 2) + b;
    time = currentTime / (duration / 2)
    if time < 1
      return change / 2 * time * time + start
    else
      time = time - 2
      return -change / 2 * (time * time - 2) + start
    end if
  end function

  function SquareEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return SquareEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return SquareEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Cubic
  ' ****************
  function CubicTween(start as float, finish as float, currentTime as float, duration as float) as float
    return CubicEaseInOut(start, finish, currentTime, duration)
  end function

  function CubicEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*(t/=d)*t*t + b
    time = currentTime / duration
    return change * time * time * time + start
  end function

  function CubicEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*((t=t/d-1)*t*t + 1) + b
    time = (currentTime / duration) - 1
    return change * (time * time * time + 1) + start
  end function

  function CubicEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if ((t/=d/2) < 1) return c/2*t*t*t + b;
    ' return c/2*((t-=2)*t*t + 2) + b
    time = currentTime / (duration / 2)
    if time < 1
      return change / 2 * time * time * time + start
    else
      time = time - 2
      return change / 2 * (time * time * time + 2) + start
    end if
  end function

  function CubicEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return CubicEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return CubicEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Quartic
  ' ****************
  function QuarticTween(start as float, finish as float, currentTime as float, duration as float) as float
    return QuarticEaseInOut(start, finish, currentTime, duration)
  end function

  function QuarticEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*(t/=d)*t*t*t + b
    time = currentTime / duration
    return change * time * time * time * time + start
  end function

  function QuarticEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' -c * ((t=t/d-1)*t*t*t - 1) + b
    time = (currentTime / duration) - 1
    return -change * (time * time * time * time - 1) + start
  end function

  function QuarticEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
    ' return -c/2 * ((t-=2)*t*t*t - 2) + b;
    time = currentTime / (duration / 2)
    if time < 1
      return change / 2 * time * time * time * time + start
    else
      time = time - 2
      return -change / 2 * (time * time * time * time - 2) + start
    end if
  end function

  function QuarticEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return QuarticEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return QuarticEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Quintic
  ' ****************
  function QuinticTween(start as float, finish as float, currentTime as float, duration as float) as float
    return QuinticEaseInOut(start, finish, currentTime, duration)
  end function

  function QuinticEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*(t/=d)*t*t*t*t + b
    time = currentTime / duration
    return change * time * time * time * time * time + start
  end function

  function QuinticEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c*((t=t/d-1)*t*t*t*t + 1) + b
    time = (currentTime / duration) - 1
    return change * (time * time * time * time * time + 1) + start
  end function

  function QuinticEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
    ' return c/2*((t-=2)*t*t*t*t + 2) + b;
    time = currentTime / (duration / 2)
    if time < 1
      return change / 2 * time * time * time * time * time + start
    else
      time = time - 2
      return change / 2 * (time * time * time * time * time + 2) + start
    end if
  end function

  function QuinticEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return QuinticEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return QuinticEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Sinusoidal
  ' ****************
  function SinusoidalTween(start as float, finish as float, currentTime as float, duration as float) as float
    return SinusoidalEaseInOut(start, finish, currentTime, duration)
  end function

  function SinusoidalEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    pi = 3.1415926535897932384626433832795
    change = finish - start
    ' -c * Math.cos(t/d * (Math.PI/2)) + c + b
    time = currentTime / duration
    return -change * Cos(time * (pi / 2)) + change + start
  end function

  function SinusoidalEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    pi = 3.1415926535897932384626433832795
    change = finish - start
    ' c * Math.sin(t/d * (Math.PI/2)) + b
    time = currentTime / duration
    return change * Sin(time * (pi / 2)) + start
  end function

  function SinusoidalEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    pi = 3.1415926535897932384626433832795
    change = finish - start
    ' -c/2 * (Math.cos(Math.PI*t/d) - 1) + b
    time = currentTime / duration
    return -change / 2 * (Cos(pi * time) - 1) + start
  end function

  function SinusoidalEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return SinusoidalEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return SinusoidalEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Exponential
  ' ****************
  function ExponentialTween(start as float, finish as float, currentTime as float, duration as float) as float
    return ExponentialEaseInOut(start, finish, currentTime, duration)
  end function

  function ExponentialEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b
    if currentTime = 0
      return start
    else
      return change * (2 ^ (10 * (currentTime / duration - 1))) + start
    end if
  end function

  function ExponentialEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b
    if currentTime = duration
      return start + change
    else
      return change * (- (2 ^ (-10 * currentTime / duration)) + 1) + start
    end if
  end function

  function ExponentialEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if (t==0) return b;
    ' if (t==d) return b+c;
    ' if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
    ' return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
    time = currentTime / (duration / 2)
    if currentTime = 0
      return start
    else if currentTime = duration
      return start + change
    else if time < 1
      return change / 2 * (2 ^ (10 * (time - 1))) + start
    else
      time = time - 1
      return change / 2 * (- (2 ^ (-10 * time)) + 2) + start
    end if
  end function

  function ExponentialEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if (t==0) return b;
    ' if (t==d) return b+c;
    ' if ((t/=d/2) < 1) return c/2 * (-Math.pow(2, -10 * t/1) + 1) + b;
    ' return c/2 * (Math.pow(2, 10 * (t-2)/1) + 1) + b;
    time = currentTime / (duration / 2)
    if currentTime = 0
      return start
    else if currentTime = duration
      return start + change
    else if time < 1
      return change / 2 * (- (2 ^ (-10 * time / 1)) + 1) + start
    else
      return change / 2 * (2 ^ (10 * (time - 2) / 1) + 1) + start
    end if
  end function

  ' ****************
  ' Circular
  ' ****************
  function CircularTween(start as float, finish as float, currentTime as float, duration as float) as float
    return CircularEaseInOut(start, finish, currentTime, duration)
  end function

  function CircularEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b
    time = currentTime / duration
    return -change * (Sqr(1 - time * time) - 1) + start
  end function

  function CircularEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' c * Math.sqrt(1 - (t=t/d-1)*t) + b
    time = (currentTime / duration) - 1
    return change * Sqr(1 - time * time) + start
  end function

  function CircularEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
    ' return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
    time = currentTime / (duration / 2)
    if time < 1
      return -change / 2 * (Sqr(1 - time * time) - 1) + start
    else
      time = time - 2
      return change / 2 * (Sqr(1 - time * time) + 1) + start
    end if
  end function

  function CircularEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return CircularEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return CircularEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Elastic
  ' ****************
  function ElasticTween(start as float, finish as float, currentTime as float, duration as float) as float
    return ElasticEaseInOut(start, finish, currentTime, duration)
  end function

  function ElasticEaseIn(start as float, finish as float, currentTime as float, duration as float, amplitude = invalid as dynamic, period = invalid as dynamic) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    pi = 3.1415926535897932384626433832795
    change = finish - start
    ' if (t==0) return b;
    ' if ((t/=d)==1) return b+c;
    ' if (!p) p=d*.3;
    ' if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
    ' else var s = p/(2*Math.PI) * Math.asin (c/a);
    ' return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
    time = currentTime / duration
    if currentTime = 0
      return start
    else if time = 1
      return start + change
    end if
    if period = invalid
      period = duration * .3
    end if
    speed = period / 4
    if amplitude = invalid or amplitude < Abs(change)
      amplitude = change
    else
      speed = period / (2 * pi) * tan(change / amplitude) ' Roku does not support Asin! Tan approximates close enough - Asin(change / amplitude)
    end if
    time = time - 1
    return - (amplitude * (2 ^ (10 * time)) * Sin((time * duration - speed) * (2 * pi) / period)) + start
  end function

  function ElasticEaseOut(start as float, finish as float, currentTime as float, duration as float, amplitude = invalid as dynamic, period = invalid as dynamic) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    pi = 3.1415926535897932384626433832795
    change = finish - start
    ' if (t==0) return b;
    ' if ((t/=d)==1) return b+c;
    ' if (!p) p=d*.3;
    ' if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
    ' else var 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);
    time = currentTime / duration
    if currentTime = 0
      return start
    else if time = 1
      return start + change
    end if
    if period = invalid
      period = duration * .3
    end if
    speed = period / 4
    if amplitude = invalid or amplitude < Abs(change)
      amplitude = change
    else
      speed = period / (2 * pi) * tan(change / amplitude) ' Roku does not support Asin! Tan approximates close enough - (change / amplitude)
    end if
    return (amplitude * (2 ^ (-10 * time)) * Sin((time * duration - speed) * (2 * pi) / period) + change + start)
  end function

  function ElasticEaseInOut(start as float, finish as float, currentTime as float, duration as float, amplitude = invalid as dynamic, period = invalid as dynamic) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    pi = 3.1415926535897932384626433832795
    change = finish - start
    ' if (t==0) return b;
    ' if ((t/=d/2)==2) return b+c;
    ' if (!p) p=d*(.3*1.5);
    ' if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
    ' else var s = p/(2*Math.PI) * Math.asin (c/a);
    ' if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
    ' return (a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b);
    time = currentTime / (duration / 2)
    if currentTime = 0
      return start
    else if time = 2
      return start + change
    end if
    if period = invalid
      period = duration * (.3 * 1.5)
    end if
    speed = period / 4
    if amplitude = invalid or amplitude < Abs(change)
      amplitude = change
    else
      speed = period / (2 * pi) * tan(change / amplitude) ' Roku does not support Asin! Tan approximates close enough - Asin(change / amplitude)
    end if
    time = time - 1
    if time < 0
      return -.5 * (amplitude * (2 ^ (10 * time)) * Sin((time * duration - speed) * (2 * pi) / period)) + start
    else
      return (amplitude * (2 ^ (-10 * time)) * Sin((time * duration - speed) * (2 * pi) / period) * .5 + change + start)
    end if
  end function

  function ElasticEaseOutIn(start as float, finish as float, currentTime as float, duration as float, amplitude = invalid as dynamic, period = invalid as dynamic) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return ElasticEaseOut(0, change, currentTime * 2, duration, amplitude, period) * .5 + start
    else
      return ElasticEaseIn(0, change, currentTime * 2 - duration, duration, amplitude, period) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Overshoot
  ' ****************
  function OvershootTween(start as float, finish as float, currentTime as float, duration as float) as float
    return OvershootEaseInOut(start, finish, currentTime, duration)
  end function

  function OvershootEaseIn(start as float, finish as float, currentTime as float, duration as float, overshoot = 1.70158 as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if (s == undefined) s = 1.70158;
    ' return c*(t/=d)*t*((s+1)*t - s) + b;
    time = currentTime / duration
    return change * time * time * ((overshoot + 1) * time - overshoot) + start
  end function

  function OvershootEaseOut(start as float, finish as float, currentTime as float, duration as float, overshoot = 1.70158 as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if (s == undefined) s = 1.70158;
    ' return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
    time = (currentTime / duration) - 1
    return change * (time * time * ((overshoot + 1) * time + overshoot) + 1) + start
  end function

  function OvershootEaseInOut(start as float, finish as float, currentTime as float, duration as float, overshoot = 1.70158 as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    ' if (s == undefined) s = 1.70158;
    ' if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
    ' return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b
    time = currentTime / (duration / 2)
    overshoot = overshoot * 1.525
    if time < 1
      return change / 2 * (time * time * ((overshoot + 1) * time - overshoot)) + start
    else
      time = time - 2
      return change / 2 * (time * time * ((overshoot + 1) * time + overshoot) + overshoot) + start
    end if
  end function

  function OvershootEaseOutIn(start as float, finish as float, currentTime as float, duration as float, overshoot = 1.70158 as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return OvershootEaseOut(0, change, currentTime * 2, duration, overshoot) * .5 + start
    else
      return OvershootEaseIn(0, change, currentTime * 2 - duration, duration, overshoot) * .5 + (change * .5) + start
    end if
  end function

  ' ****************
  ' Bounce
  ' ****************
  function BounceTween(start as float, finish as float, currentTime as float, duration as float) as float
    return BounceEaseInOut(start, finish, currentTime, duration)
  end function

  function BounceEaseIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    return change - BounceEaseOut(0, change, duration - currentTime, duration) + start
  end function

  function BounceEaseOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    time = currentTime / duration
    if time < (1 / 2.75)
      return change * (7.5625 * time * time) + start
    else if time < (2 / 2.75)
      time = time - (1.5 / 2.75)
      return change * (7.5625 * time * time + .75) + start
    else if time < (2.5 / 2.75)
      time = time - (2.25 / 2.75)
      return change * (7.5625 * time * time + .9375) + start
    else
      time = time - (2.625 / 2.75)
      return change * (7.5625 * time * time + .984375) + start
    end if
  end function

  function BounceEaseInOut(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return BounceEaseIn(0, change, currentTime * 2, duration) * .5 + start
    else
      return BounceEaseOut(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

  function BounceEaseOutIn(start as float, finish as float, currentTime as float, duration as float) as float
    if currentTime > duration or duration = 0
      return finish
    end if
    change = finish - start
    if currentTime < duration / 2
      return BounceEaseOut(0, change, currentTime * 2, duration) * .5 + start
    else
      return BounceEaseIn(0, change, currentTime * 2 - duration, duration) * .5 + (change * .5) + start
    end if
  end function

end namespace