LoginSignup
4
3

More than 5 years have passed since last update.

Spineランタイム:アニメーションの開始/終了イベントを受ける

Last updated at Posted at 2016-07-28

こまめにまとめるシリーズで、今回はアニメーション開始・終了のイベントについてです。
以下、SpineランタイムはSpine-Starlingの4.3を使います。どの言語のランタイムでも大きさな差はないと思われます。

AnimationStateのイベント

アニメーションの開始と終了イベントは、AnimationStateの各Listenersオブジェクト(後述)にコールバック登録する事で得る事ができます。コールバックに渡される引数はトラック番号および、onCompleteのみ第二引数にそのイベントの発行回数が渡されます。

sample.as
var state:AnimationState = skeletonAnimation.state;
state.onStart.add(function(track:int):void{
    trace("track#" + track + " のアニメが開始した");
});
state.onEnd.add(function(track:int):void{
    trace("track#" + track + " のアニメが停止した");
});
state.onComplete.add(function(track:int, count:int):void{
    trace("track#" + track + " のアニメが" + count + "回、完了した");
});

state.setAnimation...

onEndonCompleteの差はなんでしょうか?

onCompleteは設定されたアニメーションが最後まで再生された時に発行されるイベントです。ループアニメの場合何度もonCompleteイベントが発行されるので、その回数として第二引数にカウンタ値も渡されます。非ループアニメの場合、一度だけこれが発行されます。

対して、onEndは再生中のアニメが止まった、または、止められた際に発行されます。clearTrack命令による強制アニメ停止、次のアニメの上書き設定による停止、今のアニメが最後まで再生されて(=onComplete)の停止、、など理由はなんであれ、Trackの再生状態が解除された際に発行されます。onCompleteのタイミングでonEndも発行されます。

注意として、一つのトラックに連続アニメーションがキューに入って設定されている場合(こちらの記事参照)で、キュー全体でsetAnimationclearTrack命令で破棄された場合は、再生中TrackEntry以外はonEndイベントが発行されないという点があります。

TrackEntryのイベント

AnimationStateでまとめてではなく、アニメーション再生指示毎にイベントを受けることもできます。具体的にはTrackEntryにコールバック関数を設定します。

sample.as
var trackEntry:TrackEntry = animationState.setAnimationByName(0, "hoge");
trackEntry.onStart = function(track:int):void {
   trace("track#" + track + " のアニメが開始した");
}
trackEntry.onEnd = function(track:int):void {
    trace("track#" + track + " のアニメが停止した");
};
trackEntry.onComplete = function(track:int):void {
    trace("track#" + track + " のアニメが" + count + "回、完了した");
};

イベントの種類と挙動はAnimationStateと同じですが、提供されるのがListenersではなく、素のFunctionである事に注意です。上記のソースでは、onStartにaddせずonStartを関数でそのまま上書きしています。コールバック関数設定を解除するには、それぞれにnullを代入します。

sample.as
trackEntry.onStart = null;
trackEntry.onEnd = null;
trackEntry.onComplete = null;

Listenersとは?

FlashやStarlingのイベントモデルはEventListenerを継承・実装するクラス構成をとっていますが、そのEventListener機能をプロパティ側に抜き出してもたせような形式であるのがspine.animation.Listenersです。addしてリスナ登録、removeでリスナ登録解除となります。

sample.as
function onStart(track:int):void {
    trace("start!");
    animState.onStart.remove(onStart); // 解除
};
animState.onStart.add(onStart); // 追加

C#のイベントモデルとか、ActionScript3 Signals みたいなやつですね。EventListenerよりもスマートな実装で自分はこちらの形式の方が好きです。(Signalsについてはこちらのサイトが詳しいです。 http://www.inazumatv.com/contents/archives/5729 ) SpineのListenersはSignalsほど高機能ではないですが、Spineのランタイムライブラリ内部だけでなく、ユーザ側でも利用できるので、簡単なコードを書くときなどは利用できそうです。

連続再生用途にonEndを使わない

onEndイベントのハンドラ内(ListenersでもFunctionでも)にて次のアニメーション再生を行おうとすると、アニメーション制御がおかしくなる現象を手元で確認しました。アニメーションの連続再生用途にはaddAnimation/addAnimationByNameを使うか、onCompleteハンドラを使うかしましょう。もしonEnd内部でなんとか次アニメーションを再生しなくてはいけないシチュエーションがあるなら、1フーム待ってから次のアニメーション指示をを出すようにしましょう。

おわりに

AnimationStateとTrackEntryでイベントの仕組みが異なっているのは、無数に作られていくTrackEntryにListenersは大げさすぎるという判断でしょうか。直接関数指定の方がパフォーマンス的にも良さそうなのでそこは良いのですが、どちらにしろコールバックへの引数にはランタイムがTrackEntry自体も追加で渡してくれるともっと便利な気はしますね。

以上です。では。

4
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3