Skip to content

Instantly share code, notes, and snippets.

@jin1016
Last active March 23, 2018 15:04
Show Gist options
  • Save jin1016/7082ae225b10bf4b7bcb to your computer and use it in GitHub Desktop.
Save jin1016/7082ae225b10bf4b7bcb to your computer and use it in GitHub Desktop.
Tween.js の TJS2 版作り中
/**
JavaScript 版 Tween.js をベースに TJS2 へ書き直したものです。
開発途中です。
補完する時間指定して動かすのも何とかしたいところ。
オリジナルは MIT License です。
The MIT License
Copyright (c) 2010-2012 Tween.js authors.
Easing equations Copyright (c) 2001 Robert Penner http://robertpenner.com/easing/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
@if(__TWEEN_TJS__==0)
@set(__TWEEN_TJS__=1)
class Tweens {
var tweens_:Array;
function Tweens() {
tweens_ = new Array();
}
// Tweenを追加する。Tween開始時に自動的に追加される。
function add( tween:Tween ):void {
tweens_.add(tween);
if( tweens_.count == 1 ) {
System.addContinuousHandler(update);
}
}
// Tweenを削除する。Tween停止時に自動的に削除される。
function remove( tween:Tween ):void {
tweens_.remove( tween );
if( tweens_.count == 0 ) {
System.removeContinuousHandler(update);
}
}
// 更新処理、ContinuousHandlerから呼ばれ、更新を行う
function update( tick:int ):void {
if( tweens_.count == 0 ) {
System.removeContinuousHandler(update);
return;
}
var i:int = 0;
while( i < tweens_.count ) {
if( tweens_[i].update( tick ) ) {
i++;
} else {
tweens_.erase(i);
}
}
}
// 実行中のすべてのTweenの配列を取得する
property tweens {
getter ():Array { return tweens_; }
}
class Easing {
class Linear {
function None( k ) { return k; }
};
class Quadratic {
function In( k ) { return k*k; }
function Out( k ) { return k*(2-k); }
function InOut( k ) {
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
return - 0.5 * ( --k * ( k - 2 ) - 1 );
}
};
class Cubic {
function In( k ) { return k*k*k; }
function Out( k ) { return --k * k * k + 1; }
function InOut( k ) {
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k;
return 0.5 * ( ( k -= 2 ) * k * k + 2 );
}
};
class Quartic {
function In( k ) { return k * k * k * k; }
function Out( k ) { return 1 - ( --k * k * k * k ); }
function InOut( k ) {
if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k;
return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 );
}
};
class Quintic {
function In( k ) { return k * k * k * k * k; }
function Out( k ) { return --k * k * k * k * k + 1; }
function InOut( k ) {
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k;
return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
}
};
class Sinusoidal {
function In( k ) { return 1 - Math.cos( k * Math.PI / 2 ); }
function Out( k ) { return Math.sin( k * Math.PI / 2 ); }
function InOut( k ) { return 0.5 * ( 1 - Math.cos( Math.PI * k ) ); }
};
class Exponential {
function In( k ) { return k === 0 ? 0 : Math.pow( 1024, k - 1 ); }
function Out( k ) { return k === 1 ? 1 : 1 - Math.pow( 2, - 10 * k ); }
function InOut( k ) {
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 1024, k - 1 );
return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 );
}
};
class Circular {
function In( k ) { return 1 - Math.sqrt( 1 - k * k ); }
function Out( k ) { return Math.sqrt( 1 - ( --k * k ) ); }
function InOut( k ) {
if ( ( k *= 2 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1);
return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1);
}
};
class Elastic {
function In( k ) {
var s, a = 0.1, p = 0.4;
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( !a || a < 1 ) { a = 1; s = p / 4; }
else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
}
function Out( k ) {
var s, a = 0.1, p = 0.4;
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( !a || a < 1 ) { a = 1; s = p / 4; }
else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
}
function InOut( k ) {
var s, a = 0.1, p = 0.4;
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( !a || a < 1 ) { a = 1; s = p / 4; }
else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
}
};
class Back {
function In( k ) {
var s = 1.70158;
return k * k * ( ( s + 1 ) * k - s );
}
function Out( k ) {
var s = 1.70158;
return --k * k * ( ( s + 1 ) * k + s ) + 1;
}
function InOut( k ) {
var s = 1.70158 * 1.525;
if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
}
};
class Bounce {
function In( k ) {
return 1 - global.Tweens.Easing.Bounce.Out( 1 - k );
}
function Out( k ) {
if ( k < ( 1 / 2.75 ) ) {
return 7.5625 * k * k;
} else if ( k < ( 2 / 2.75 ) ) {
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
} else if ( k < ( 2.5 / 2.75 ) ) {
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
} else {
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
}
}
function InOut( k ) {
if ( k < 0.5 ) return global.Tweens.Easing.Bounce.In( k * 2 ) * 0.5;
return global.Tweens.Easing.Bounce.Out( k * 2 - 1 ) * 0.5 + 0.5;
}
};
};
// { frames:[], values:[] } を使ってキーフレームアニメーションも可能にする
class Interpolation {
function Linear( v:Array, k:real, frames:Array=null ):real {
var m:int = v.count - 1;
var f:real = m * k;
if( k < 0 ) return UtilLenear( v[0], v[1], f );
if( k > 1 ) return UtilLenear( v[m], v[m - 1], m - f );
if( frames === null ) {
var i = Math.floor( f );
return UtilLenear( v[i], v[i + 1 > m ? m : i + 1], f - i );
} else {
var range:int = searchRange( frames, k );
if( range < 0 ) { // out of range
return v[m];
}
var minval:real = v[range];
var maxval:real = v[range+1];
var ragneval:real = frames[range+1]-frames[range];
return UtilLenear( minval, maxval, (k-frames[range])/rangeval );
}
}
function searchRange( frames:Array, k:real ):int {
var range:int = -1;
var fc:int = frames.count;
for( var i:int = 0; i < (fc-1); i++ ) {
if( k <= frames[i] ) {
range = i;
break;
}
}
return range;
}
function Bezier( v:Array, k:real, frames:Array=null ):real {
if( frames === null ) {
var b:real = 0;
var n:int = v.count - 1;
for( var i:int = 0; i <= n; i++ ) {
b += Math.pow( 1 - k, n - i ) * Math.pow( k, i ) * v[i] * UtilBernstein( n, i );
}
return b;
} else {
var range:int = searchRange( frames, k );
if( range < 0 ) { // out of range
return v[m];
}
var ragneval:real = frames[range+1]-frames[range];
var val:real = (k-frames[range])/rangeval;
var start:int = range*2;
return BezierRange( v, start, start+4, val );
}
}
function BezierRange( v:Array, start:int, end:int, k:real ):real {
var b:real = 0;
var n:int = end-start-1;
for( var i:int = 0; i <= n; i++ ) {
b += Math.pow( 1 - k, n - i ) * Math.pow( k, i ) * v[start+i] * UtilBernstein( n, i );
}
return b;
}
function CatmullRom( v:Array, k:real, frames:Array=null ):real {
if( frames === null ) {
var m:int = v.count - 1;
var f:real = m * k;
var i = Math.floor( f );
if( v[0] === v[m] ) {
if( k < 0 ) i = Math.floor( f = m * ( 1 + k ) );
return UtilCatmullRom( v[( i - 1 + m ) % m], v[i], v[( i + 1 ) % m], v[( i + 2 ) % m], f - i );
} else {
if( k < 0 ) return v[0] - ( UtilCatmullRom( v[0], v[0], v[1], v[1], -f ) - v[0] );
if( k > 1 ) return v[m] - ( UtilCatmullRom( v[m], v[m], v[m - 1], v[m - 1], f - m ) - v[m] );
return UtilCatmullRom( v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i );
}
} else {
}
}
function UtilLenear( p0:real, p1:real, t:real ):real { return ( p1 - p0 ) * t + p0; }
function UtilBernstein( n:int, i:int ):real {
if( n < i ) return 0;
if( i == 0 ) return 1;
if( i == 1 ) return n;
return UtilBernsteinFact( n ) / (UtilBernsteinFact( i ) * UtilBernsteinFact( n - i ));
}
function UtilBernsteinFact( n:int ):real {
if( n == 0 ) return 1;
if( n <= 2 ) return n;
var d:real = n;
var ne:real = Math.sqrt( 2 * Math.PI * d ) * Math.pow( ( d / Math.exp( 1 ) ), d );
return( ne * Math.exp( 1 / ( 12 * d ) - 1 / ( 360 * Math.pow( d, 3 ) ) + 1 / ( 1260 * Math.pow( d, 5 ) ) ) );
}
/*
function Bernstein( n , i ) {
var fc = Tweens.Interpolation.Utils.Factorial;
return fc( n ) / fc( i ) / fc( n - i );
};
Factorial: function () {
var a = [ 1 ];
return function ( n ) {
var s = 1, i;
if ( a[ n ] ) return a[ n ];
for ( i = n; i > 1; i-- ) s *= i;
return a[ n ] = s;
};
};
*/
function UtilCatmullRom( p0:real, p1:real, p2:real, p3:real, t:real ):real {
var v0 = ( p2 - p0 ) * 0.5;
var v1 = ( p3 - p1 ) * 0.5;
var t2 = t * t;
var t3 = t * t2;
return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
}
};
};
class Tween {
var object_; // target object, object_["property"] = value;
var valuesStart_;
var valuesEnd_; // Array or number
var valuesStartRepeat_;
var duration_:real;
var repeat_:number;
var yoyo_:bool;
var isPlaying_:bool;
var reversed_:bool;
var delayTime_:number;
var startTime_:number;
// イージング関数
var easingFunction_;
// 補間関数
var interpolationFunction_;
// chainedTweens_ に入れると、今のが実行終わると次に移るようになる
var chainedTweens_:Array;
// 更新するプロパティ名のリスト
var propertyNames_:Array;
var onStartCallbackFired_:bool;
var onStartCallback_;
var onUpdateCallback_;
var onCompleteCallback_;
var onStopCallback_;
function Tween( target ) {
object_ = target;
easingFunction_ = Tweens.Easing.Linear.None;
interpolationFunction_ = Tweens.Interpolation.Linear;
chainedTweens_ = new Array();
propertyNames_ = new Array();
duration_ = 1000; // 1sec
repeat_ = 0;
yoyo_ = false;
isPlaying_ = false;
reversed_ = false;
delayTime_ = 0;
startTime_ = 0;
onStartCallbackFired_ = false;
onStartCallback_ = null;
onUpdateCallback_ = null;
onCompleteCallback_ = null;
onStopCallback_ = null;
}
// ゴール値設定
// properties : 動かす値とその最終値の辞書
// duration : 動作時間(msec)
// exp. .to( %["x":100,"y":200], 1000 ); // 1秒でxを100に
function to( properties:Dictionary, duration:real ) {
duration_ = duration;
valuesEnd_ = properties;
// copy keys
propertyNames_.clear();
var ar:Array = new Array();
ar.assign( properties );
var count:int = ar.count;
for( var i:int = 0; i < count; i += 2 ) {
propertyNames_.add( ar[i] );
}
return this;
}
// 開始
function start():Tween {
global.TweensOwener.add( this );
isPlaying_ = true;
onStartCallbackFired_ = false;
valuesStart_ = new Dictionary();
valuesStartRepeat_ = new Dictionary();
var count:int = propertyNames_.count;
for( var i:int = 0; i < count; i++ ) {
var key:string = propertyNames_[i];
valuesStart_[key] = object_[key];
if( (valuesStart_[key] instanceof "Array") != true ) {
valuesStart_[key] *= 1.0;
}
valuesStartRepeat_[key] = valuesStart_[key];
if( valuesEnd_[key] instanceof "Array" ) {
if( valuesEnd_[key].count === 0 ) {
continue;
}
var old:Array = valuesEnd_[key];
valuesEnd_[key] = new Array();
valuesEnd_[key].count = old.count+1;
valuesEnd_[key].assign(old);
valuesEnd_[key].insert( 0, object_[key] );
}
}
startTime_ = System.getTickCount();
startTime_ += delayTime_;
return this;
}
// 停止
function stop():Tween {
if( !isPlaying_ ) {
return this;
}
global.TweensOwener.remove( this );
isPlaying_ = false;
if( onStopCallback_ !== null ) {
onStopCallback_();
}
this.stopChainedTweens();
return this;
}
function stopChainedTweens() {
var numChainedTweens:int = chainedTweens_.count();
for( var i:int = 0; i < numChainedTweens; i++ ) {
chainedTweens_[i].stop();
}
}
property delay {
setter( amount:real ) { delayTime_ = amount; }
getter():real { return delayTime_; }
}
property repeat {
setter( times:int ) { repeat_ = times; }
getter():int { return repeat_; }
}
// ヨーヨー、再生・逆転再生する繰り返し
property yoyo {
setter( yoyo ) { yoyo_ = yoyo; }
getter() { return yoyo_; }
}
// 動き関数
property easing {
setter( easing ) { easingFunction_ = easing; }
getter() { return easingFunction_; }
}
// 補間関数
property interpolation {
setter( interpolation ) { interpolationFunction_ = interpolation; }
getter() { return interpolationFunction_; }
}
function addChain( t:Tween ):void {
chainedTweens_.add( t );
}
property onStart {
setter( callback ) { onStartCallback_ = callback; }
getter() { return onStartCallback_; }
}
property onUpdate {
setter( callback ) { onUpdateCallback_ = callback; }
getter() { return onUpdateCallback_; }
}
property onComplete {
setter( callback ) { onCompleteCallback_ = callback; }
getter() { return onCompleteCallback_; }
}
property onStop {
setter( callback ) { onStopCallback_ = callback; }
getter() { return onStopCallback_; }
}
function update( tick ):bool {
if( tick < startTime_ ) {
return true;
}
if( onStartCallbackFired_ == false ) {
if( onStartCallback_ !== null ) {
onStartCallback_();
}
onStartCallbackFired_ = true;
}
// 0 ~ 1 に丸める
var elapsed:real = ( tick - startTime_ ) / duration_;
elapsed = elapsed > 1 ? 1 : elapsed;
var value:real = easingFunction_( elapsed );
var count:int = propertyNames_.count;
for( var i:int = 0; i < count; i++ ) {
var key:string = propertyNames_[i];
var start = valuesStart_[key];
var end = valuesEnd_[key];
if( end instanceof "Array" ) {
object_[key] = interpolationFunction_( end, value );
} else {
if( typeof(end) === "String" ) {
end = start + (real)end;
}
object_[key] = start + ( end - start ) * value;
}
}
if( onUpdateCallback_ !== null ) {
onUpdateCallback_( value );
}
if( elapsed == 1 ) { // 末尾まで到達
if( repeat_ > 0 ) {
// リピート処理
if( repeate_ != Infinity ) {
repeate_--;
}
// ループ開始値を入れる
for( var i:int = 0; i < count; i++ ) {
var key:string = propertyNames_[i];
if( typeof( valuesEnd_[key] ) === "String" ) {
valuesStartRepeat_[key] = valuesStartRepeat_[key] + (real)valuesEnd_[key];
}
if( yoyo_ ) {
var tmp = valuesStartRepeat_[key];
valuesStartRepeat_[key] = valuesEnd_[key];
valuesEnd_[key] = tmp;
}
valuesStart_[key] = valuesStartRepeat_[key];
}
if( yoyo_ ) {
reversed_ != reversed_;
}
startTime = tick + delayTime;
return true;
} else {
// 終了処理, コンプリート
if( onCompleteCallback_ !== null ) {
onCompleteCallback_();
}
var numChainedTweens:int = chainedTweens_.count;
for( var i:int = 0; i < numChainedTweens; i++ ) {
//chainedTweens_[i].start( tick );
chainedTweens_[i].start();
}
return false;
}
}
return true;
}
};
var TweensOwener = new Tweens();
@endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment