# アニメーションの適用

Spineには、アニメーションを適用するための2つのAPIが用意されています。

# AnimationState API

[AnimationState](/spine-api-reference#AnimationState)は後で再生するアニメーションをキューすることや、アニメーション間でのミキシング(クロスフェード)、複数アニメーションを重ねて適用する(レイヤリング)など時間の経過を伴うアニメーションの適用をサポートします。

AnimationStateはステートフル、つまり処理状態を把握し、アニメーションを適用するためにアニメーションの時間やその他のパラメーターを保管します。1つのAnimationStateで複数のスケルトンのポーズを取らせるもできますが、複数のスケルトンに全く同じポーズを取らせることは稀です。通常、各[Skeleton](/spine-api-reference#Skeleton)インスタンスに1つのAnimationStateインスタンスが使用されます。

AnimationStateは[Timeline API](#Timeline-API)上で構築され、逆再生を除くほとんどのアニメーション再生のニーズに対応できます。逆再生が必要な場合、Timeline APIを直接使用するか、Spine内でボックス選択[スケーリング](/spine-dopesheet#ボックス選択)を使用してアニメーションを複製し、逆にしてください。

AnimationStateの`update`メソッドは、最後に呼び出された時からの経過時間を受け取り、内部のステートを更新します。`apply`メソッドはスケルトンを受け取り、適切なアニメーションを適用します。

```
AnimationState state = ...
.
// Every frame:
state.update(delta);
state.apply(skeleton);
```

## ミックスタイム

AnimationStateインスタンスの作成には[AnimationStateData](/spine-api-reference#AnimationStateData)を指定する必要があります。AnimationStateが現在のアニメーションを変更すると、AnimationStateDataに定義されているミックスデュレーションを使ってアニメーションを自動的にミックス(クロスフェード)するため、アニメーションを自然に移行できます。

```
AnimationStateData stateData = new AnimationStateData(skeletonData);
stateData.setDefaultMix(0.1);
stateData.setMix("walk", "jump", 0.2);
stateData.setMix("jump", "walk", 0.4);
stateData.setMix("jump", "run", 0.25);
stateData.setMix("walk", "shoot", 0);
AnimationState state = new AnimationState(stateData);
```

ミックスデュレーションを全てのアニメーションペアに手動で設定する代わりに、デフォルトのミックスデュレーションを設定できます。またミックスデュレーションはTrackEntry [mixDuration](/spine-api-reference#TrackEntry-mixDuration)プロパティを使ってケース毎に設定できます:

```
TrackEntry entry = state.setAnimation(0, "walk", true, 0);
entry.mixDuration = 0.6;
```

「Data」というサフィックス(接尾辞)に示される通り、AnimationStateDataはステートレス、つまり処理状態を把握しません。同じAnimationStateDataインスタンスを複数のAnimationStateに使用できます。

## トラック

トラックはアニメーションをレイヤーで適用することを可能にします。各トラックはアニメ―ションと再生パラメーターを保管します。トラックはゼロから昇順に番号が付けられます（トラックインデックスは、内部的には配列のインデックスです）。AnimationStateがスケルトンに適用されると、トラック番号が低いものから順にアニメーションが適用されます。

トラックには様々な用途があります。例えば、一部の要素にだけキーを作成したアニメーションを上位のトラックで再生することで、キーが作成された要素だけを下位トラックにオーバーライドできます。トラック0は歩く、走る、泳ぐなどのアニメーションに設定し、トラック1は腕と銃の発射のみにキーを作成した射撃のアニメーションにするなどです。また上位のトラックにTrackEntry [alpha](/spine-api-reference#TrackEntry-alpha)を設定することで、その下のトラックとミックスすることが可能になります。例えば、トラック0を歩くアニメーションに設定し、トラック1を足を引きずるアニメーションに設定して、プレーヤーが怪我を負うにつれトラック1のアルファを増加するように設定すれば、足をもっと引きずるようにできます。

## 再生

アニメーションのトラック設定は[setAnimation](/spine-api-reference#AnimationState-setAnimation)を呼び出すことで行います。これはトラック上の現在のアニメーションとキューされたアニメーションを指定したアニメーションに置き換えます。ミックスデュレーションが前のアニメーションと現在のアニメーションの間で定義される場合、現在のアニメーションがミックスデュレーション中にミックスされるため、アニメーション間のトランジションがスムーズに行われます。

`setAnimation`は再生をカスタマイズする様々な方法を提供する「[TrackEntry](#TrackEntry)」を返します。

デフォルトでは、別のアニメーションが再生されるか、トラックがクリアされるまで、アニメーションが適用され続けます。特定の時間が経過した後にアニメーションを停止するには、TrackEntry [trackEnd](/spine-api-reference#TrackEntry-trackEnd)時間を設定します。

## キューイング

次に再生するアニメーションをキューするには、[addAnimation](/spine-api-reference#AnimationState-addAnimation)を呼び出します。これにより、現在または最後にそのトラックにキューされたアニメーションの後にそのアニメーションを再生するように設定できます。トラックが空の場合、`setAnimation`を呼び出したのと同様になります。

`addAnimation`は再生のカスタマイズに使用できる[TrackEntry](#TrackEntry)を返します。

## 空のアニメーション

トラックにアニメーションが何も設定されていない時に新しくアニメーションが設定された場合、直ちに再生が開始されます。代わりに、セットアップポーズからアニメーションをミックスインするには、空のアニメーションを使用できます。

また、トラックがクリアされると、トラックのアニメーションは適用されなくなり、スケルトンは現在のポーズのままになります。代わりに、アニメーションをセットアップポーズにミックスアウトしたい場合も、空のアニメーションを使用できます。

空のアニメーションにはタイムラインがありません。これはプレースホルダー(一時的な保管場所)として使用され、ミックスデュレーションを設定することができます。空のアニメーションを設定またはキューに入れるために、[setEmptyAnimation](/spine-api-reference#AnimationState-setEmptyAnimation) および [addEmptyAnimation](/spine-api-reference#AnimationState-addEmptyAnimation) メソッドが用意されています。

セットアップポーズからアニメーションをミックスインするには、以下のようにまず空のアニメーションを設定し、ミックスインするアニメーションを追加し、mixDurationを設定します。

```
state.setEmptyAnimation(track, 0);
TrackEntry entry = state.addAnimation(track, "run", true, 0);
entry.mixDuration = 1.5;
```

アニメーションをセットアップポーズにミックスアウトするには、ミックスデュレーションを指定して空のアニメーションを設定またはキューします：

```
state.setAnimation(track, "run", true, 0);
state.addEmptyAnimation(track, 1.5, 0);
```

アニメーションがTrackEntry [trackEnd](/spine-api-reference#TrackEntry-trackEnd)時間に達すると、そのアニメーション中でキーが作成されている各プロパティにセットアップポーズを設定し、トラックがクリアされます。即座にセットアップポーズに戻す代わりに、`setEmptyAnimation` または `addEmptyAnimation` を使用してスケルトンをセットアップポーズにミックスして戻す方が望ましい場合があります。

## TrackEntry

アニメーションをセットしたり、キューに追加したりするメソッドはTrackEntryを返します。これは再生のカスタマイズに使用できます。TrackEntryで利用できる各種プロパティについては、[TrackEntryのAPIリファレンス](/spine-api-reference#TrackEntry)をご覧ください。

### 参照

TrackEntryへの参照を保持することも可能です。例えば、時間の経過とともに`alpha`または`timeScale`プロパティを調整することができます。しかし`dispose`リスナーイベントの発生タイミングを過ぎても参照を保持してしまわないように注意する必要があります。

## リスナー

アプリケーションはTrackEntryのライフサイクルイベントの通知を受けるためにコールバックを登録することができます。AnimationStateの`addListener`は全てのTrackEntryイベントにリスナーを登録します。また、特定のTrackEntryにリスナーを設定し、そのエントリーからのみイベントを受け取ることも可能です。

利用可能なイベントは[AnimationStateListener](/spine-api-reference#AnimationStateListener)に記載されており、指定された順序で発生することが保証されています。イベントはAnimationStateの `update` または `apply` メソッドにより内部処理の間にキューされ、リスナーにはその後、メソッドが返る直前に通知されます。これにより、リスナーはアニメーションをセットしたりトラックをクリアするなどのAnimationStateの操作を安全に実行できます。しかしすでにキューされたイベントは[clearListenerNotifications](/spine-api-reference#AnimationState-clearListenerNotifications)が使用されない限りすべて発生します。

新しいアニメーションの設定など、リスナー内で行われたAnimationStateへの変更は、次にAnimationState `apply`が呼び出されるまでスケルトンに適用されません。これはリスナー内で行うことができますが、最初に `update` を呼び出すように注意する必要があります：

```
// Inside a listener:
state.setAnimation(0, "jump", false);
state.update(0); // Advance internal state.
state.apply(skeleton);
```

`apply`メソッドは内部の状態を変更せずに単一のAnimationStateを複数のスケルトンに適用することができます。`update`を呼び出すことで、AnimationStateは、全ての適用が完了して後続の`apply`呼び出しが次のフレームで行われることを知ることができます。`update`が呼び出されない場合、`apply`は同じリスナー通知を引き起こしてしまう可能性があり、無限ループやスタックオーバーフローの原因となります。

# Timeline API

Timeline APIは、[Animation](/spine-api-reference#Animation)クラスと[Timeline](/spine-api-reference#Timeline)クラスにより構成されるアニメーション適用の最下層のAPIです。これらのクラスはステートレス、つまり処理状態を把握しないため、アニメーションを適用するための時間やその他のパラメータを外部に保存して操作する必要があります。このAPIはアニメーションの再生を最もコントロールしやすいですが、再生状態の管理に多くの作業を必要とします。そのため、ほとんどのユーザーは[AnimationState API](#AnimationState-API)を使用することを選ぶでしょう。

Animationは名前とTimelineのリストを持つ非常にシンプルなものです。各タイムラインが、スケルトンのプロパティを時間経過に伴いどのように変更するかを把握しています。アニメーションをスケルトンに適用するには、アニメーション内の各タイムラインに[apply](/spine-api-reference#Timeline-apply)を呼び出す必要があります。

```
time += delta;
alpha = 1; // For mixing between the current or setup pose (0) or the animation pose (1).
blend = MixBlend.first; // How the current or setup pose is mixed with the animation pose.
direction = MixDirection.in; // Whether mixing out to the setup pose or in to the animation pose.

for (Timeline timeline : animation.timelines)
	timeline.apply(skeleton, lastTime, time, events, alpha, blend, direction);

// The events list contains any events fired between lastTime and time.
// Process them here, then clear the list.
events.clear();

lastTime = time;
```

Animationは`loop`パラメータを持ち、各タイムラインで`apply`を呼び出すだけの便利な`apply`メソッドを持っています。

```
loop = true;
animation.apply(skeleton, lastTime, time, loop, events, alpha, blend, direction);
```


[次: ランタイムスケルトン](/spine-runtime-skeletons)
[前: スケルトンデータのロード](/spine-loading-skeleton-data)
[Spine Runtimes ガイド: 目次]