# spine-cppランタイムドキュメント

> **ライセンスについて**
>
> Spineランタイムをアプリケーションに組み込む前に、必ず[Spine Runtimes License](/spine-runtimes-license)を確認してください。

<style>.colortable td{vertical-align:middle}</style>!!

# はじめに
spine-cppとは、C++とネイティブに連携できる言語で書かれたゲームエンジンやフレームワークにSpineのアニメーションを組み込むための汎用ランタイムです。

spine-cppは、以下の機能を提供します:

* JSONまたはバイナリ形式でエクスポートされた[Spineスケルトンのロード](/spine-loading-skeleton-data)。
* Spineスケルトンで使用される画像が保管されている[テクスチャアトラスのロード](/spine-loading-skeleton-data)。
* [スキン](/spine-runtime-skins)の管理およびスケルトンへの適用。 
* [アニメーション](/spine-applying-animations)の管理およびスケルトンへの適用。 
* 現在の[スケルトンのポーズ、スロットおよびアタッチメントの状態](/spine-runtime-skeletons)に基づいて、レンダリングと物理に必要なデータの操作および計算。

spine-cppランタイムはエンジンに依存しない汎用ランタイムなので、ユーザー自身が、エンジン固有のファイル入出力や画像のロードをspine-cppランタイムに提供するための関数群を実装し、spine-cppランタイムが生成したデータをエンジンの描画システムで描画し、さらにラグドールなどの高度なユースケースが要求される場合にはオプションとしてエンジンの物理システムとデータを統合する必要があります。

spine-cppランタイムは、幅広いプラットフォームとコンパイラとの互換性を保証するためにC++11で記述されています。

また、他の公式Spineランタイムはspine-cppをベースにしているため、お好みのエンジンとの統合のためのサンプルとして利用することができます:

* [spine-cocos2dx](/git/spine-runtimes/tree/spine-cocos2dx): [Cocos2D-x](http://www.cocos2d-x.org/)用のランタイム。
* [spine-glfw](/git/spine-runtimes/tree/spine-glfw): OpenGL+3.3用のランタイムで、[GLFW](https://www.glfw.org/)ベースの例があります。
* [spine-sfml](/git/spine-runtimes/tree/spine-sfml/cpp): [SFML](http://www.sfml-dev.org/)用のランタイムであり、最もシンプルなspine-cppベースのランタイム。
* [spine-sdl](/spine-sdl): [SDL](https://www.libsdl.org/)用のランタイム。
* [spine-ue](/spine-ue): [Unreal Engine](https://www.unrealengine.com/)用のランタイム。

以下の各セクションでは、spine-cppランタイムの概要とその使用方法について、エンジンに依存しない形で簡単に説明します。spine-cppをベースにした公式Spineランタイムのほとんどは、spine-cpp APIの一部を独自の使いやすいAPIにカプセル化しています。しかし、基盤となるspine-cppランタイムの基本を理解しておくことは有益です。

> **注意:** 当ガイドでは、Spineで使用される基本的な[ランタイムのアーキテクチャ](/spine-runtime-architecture)と用語を理解されていることを前提としています。ランタイムのより高度な機能については、[APIリファレンス](/spine-api-reference)も参照してください。

# Spineアセットのspine-cpp向けエクスポート
![](/img/spine-runtimes-guide/editor-export-window.png)

以下の実行方法については、Spineユーザーガイド内で紹介されています :

1. JSONまたはバイナリ形式での[スケルトン＆アニメーションデータのエクスポート](/spine-export)
2. [スケルトンの画像を含むテクスチャアトラスのエクスポート](/spine-texture-packer)

スケルトンデータとテクスチャアトラスをエクスポートすると、以下のファイルが得られます :

![](/img/spine-runtimes-guide/exported-files.png)

1. `skeleton-name.json`または`skeleton-name.skel`：　これはスケルトンとアニメーションのデータを含んでいます。
2. `skeleton-name.atlas`：　これはテクスチャアトラスの情報を含んでいます。
3. １つまたは複数の`.png`ファイル：　これはテクスチャアトラスの各ページで、スケルトンが使用するイメージを含んでいます。

> **補足:** 拡張子が `.skel` のバイナリフォーマットの方が軽量でロードが速いです。

> **注意:** スケルトンごとに1つのテクスチャアトラスを作成するのではなく、複数のスケルトンの画像を1つのテクスチャアトラスにパックすることもできます。詳しくは[テクスチャパッキングのガイド](/spine-texture-packer)をご覧ください。

# Spineアセットのロード
spine-cppは、テクスチャアトラス、Spineスケルトンデータ（ボーン、スロット、アタッチメント、スキン、アニメーション）をロードし、[AnimationStateData](/spine-applying-animations#ミックスタイム)によってアニメーション間のミックスタイムを定義するためのAPIを提供します。この3種類のデータはセットアップポーズデータとも呼ばれ、通常、一度ロードされた後はすべてのゲームオブジェクトで共有されます。この共有の仕組みは、各ゲームオブジェクトに独自のスケルトンと[AnimationState](/spine-applying-animations#AnimationState-API)を与えることで実現されており、インスタンスデータとも呼ばれています。

> **補足:** ローディングの全体的なアーキテクチャの詳細については、全般的な[Spineランタイムドキュメント](/spine-loading-skeleton-data)を参照してください。

## テクスチャアトラスのロード
テクスチャアトラスデータは、アトラスページ内の個々の画像の位置を記述したカスタム[アトラス形式](/spine-atlas-format)で保存されます。アトラスページ自体はアトラスとは別にプレーンな`.png`ファイルとして保存されます。

`Atlas`クラスは、このタスクのために、[ディスクからアトラスファイルをロードする](/git/spine-runtimes/blob/spine-cpp/spine-cpp/include/spine/Atlas.c#L116)コンストラクタと、[rawインメモリデータからアトラスファイルをロードする](/git/spine-runtimes/blob/spine-cpp/spine-cpp/include/spine/Atlas.c#L118)コンストラクタを提供します。アトラスのロードに失敗した場合、デバッグモードでassertが発生します。

```
#include <spine/spine.h>

using namespace spine;

// ファイルからアトラスをロードします。
// 最後の引数はエンジン固有で、各テクスチャアトラスページの画像をロードし、
// レンダリングに使用できるエンジン固有のテクスチャやマテリアルに変換する役割を果たします。
Atlas* atlas = new Atlas("myatlas.atlas", textureLoader);

// メモリからアトラスをロードします。
// メモリの場所、バイト数、アトラスページテクスチャをロードするディレクトリを指定します。
Atlas* atlas = new Atlas(atlasInMemory, atlasDataLengthInBytes, dir, textureLoader);
```

## スケルトンデータのロード
スケルトンデータ (ボーン、スロット、コンストレイント、アタッチメント、スキン、アニメーション)は、ヒューマン・リーダブル(対人可読形式)な[JSON](/spine-json-format)または[バイナリ形式](/spine-binary-format)でエクスポートできます。spine-cppはスケルトンデータを `spSkeletonData` クラスインスタンスに格納します。

JSON形式のエクスポートファイルからスケルトンデータを読み込むために、`SkeletonJson` インスタンスを作成し、先にロードした `Atlas` を受け取り、スケルトンのスケールを設定し、最後にファイルからスケルトンデータを読み込むようにします:

```
#include <spine/spine.h>

using namespace spine;

// ロードに使用するSkeletonJsonを作成(create)し、
// ロードしたデータが元データの2倍の大きさになるようにスケールを設定する
SkeletonJson json(atlas);
json.setScale(2);

// スケルトンの.jsonファイルをSkeletonDataに読み込む
SkeletonData* skeletonData = json.readSkeletonDataFile(filename);

// ロードに失敗した場合は、エラーを表示してアプリを終了する
if (!skeletonData) {
	printf("%s\n", json.getError().buffer());
	exit(0);
}
```

バイナリ形式のエクスポートファイルからスケルトンデータをロードする場合も、代わりに `SkeletonBinary` を使用する以外は同じです:

```
// ロードに使用するSkeletonBinaryを作成(create)し
// ロードしたデータが元データの2倍の大きさになるようにスケールを設定する
SkeletonBinary binary(atlas);
binary.setScale(2);

// スケルトンの.skelファイルをSkeletonDataに読み込む
SkeletonData* skeletonData = binary.readSkeletonDataFile(filename);

// ロードに失敗した場合は、エラーを表示してアプリを終了する
if (!skeletonData) {
	printf("%s\n", binary.getError().buffer());
	exit(0);
}
```

## AnimationStateDataの準備
Spineは、あるアニメーションから別のアニメーションに切り替える際のスムーズなトランジション（クロスフェード）に対応しています。このクロスフェードは、あるアニメーションと別のアニメーションを指定したミックスタイムの間だけミックスすることで実現されています。spine-cppランタイムはこれらのミックスタイムを定義するために `AnimationStateData` 構造体を提供します:

```
#include <spine/spine.h>

using namespace spine;

// spAnimationStateDataを作成(create)する
AnimatonStateData* animationStateData = new AnimationStateData(skeletonData);

// 任意のアニメーションのペア間のデフォルトのミックスタイムを秒単位で設定する
animationStateData->setDefaultMix(0.1f);

// "jump"から"walk"までのアニメーション間のミックスタイムを0.2秒に設定し、
// この前後のペアのデフォルトのミックスタイムを上書きする
animationStateData->setMix("jump", "walk", 0.2f);
```

`AnimationStateData` で定義されたミックスタイムは、アニメーションの適用時に明示的に上書きすることも可能です（後述）。

# スケルトン
セットアップポーズデータ（スケルトンデータ、テクスチャアトラス）は、各ゲームオブジェクト間で共有されることが前提になっています。spine-cppでは、この共有を容易にするために、`Skeleton` 構造体を提供しています。各ゲームオブジェクトは、自分自身の `Skeleton` インスタンスを受け取り、そのインスタンスはデータソースとして `SkeletonData` および `Atlas` インスタンスを参照します。

`Skeleton` は、ボーンをプロシージャルに変更したり、アニメーションを適用したり、ゲームオブジェクトに固有のアタッチメントやスキンを設定するなど、自由に変更できますが、基盤となるスケルトンデータやテクスチャアトラスには何ら影響しません。こうすることで、`SkeletonData` および `Atlas` インスタンスを、任意の数のゲームオブジェクト間で共有することができます。

## スケルトンの作成
`Skeleton` インスタンスを作成するには:

```
Skeleton* skeleton = new Skeleton(skeletonData);
```


すべてのゲームオブジェクトは、それ自身の `Skeleton` を必要とします。データの大部分は`SkeletonData` と `Atlas` に残り、すべての `Skeleton` メモリの消費とテクスチャの切り替えを大幅に削減します。したがって、`Skeleton` のライフタイム(寿命)は、対応するゲームオブジェクトのライフタイムと連動しています。

## ボーン
スケルトンはボーンによる階層構造で、ボーンにスロットが、スロットにアタッチメントが取り付けられています。

### ボーンを探す
スケルトンに含まれるすべてのボーンは、そのスケルトンから取得できる一意の名前を持ちます:

```
// その名前のボーンが見つからなかった場合、0 を返します。
Bone* bone = skeleton->findBone("mybone");
```

### ローカルトランスフォーム
ボーンは、rootボーンに戻るまで、その親ボーンに影響されます。例えば、あるボーンを回転させると、そのすべての子ボーンと、さらにそれらのすべての子ボーンも回転されます。これらの階層的なトランスフォームを達成するために、各ボーンは、以下の要素からなる親ボーンに相対するローカルトランスフォームを持っています:

* 親を基準とした `x`、`y` 座標。
* 度単位の `rotation(回転)`。
* `scaleX(スケールX)`、`scaleY(スケールY)`。
* 度単位の `shearX(シアーX)`、`shearY(シアーY)`。

ボーンのローカルトランスフォームは、プロシージャルな方法、またはアニメーションの適用によって操作することができます。前者では、ボーンがマウスカーソルを指すようにしたり、足のボーンを地形に沿わせたりといった動的な動作を実装することができます。また、ローカルトランスフォームのプロシージャルな変更と、アニメーションの適用は同時に行うことができます。最終的には、1つのローカルトランスフォームを組み合わせたものになります。

### ワールドトランスフォーム
ボーンのローカルトランスフォームをプロシージャルに変更するか、アニメーションを適用するかによって全てのローカルトランスフォームが設定されると、レンダリングと物理のために各ボーンのワールドトランスフォームが必要になります。

この計算はrootボーンから始まり、すべての子ボーンのワールドトランスフォームを再起的に計算します。この計算では、アーティストがSpineエディター内で定義した[IK](/spine-ik-constraints)、[トランスフォーム](/spine-transform-constraints)、[パス](/spine-path-constraints)などのコンストレイントも適用されます。 

ワールドトランスフォームを計算するには、まずスケルトンのフレーム時間を物理用に更新し、次に実際のトランスフォームを計算する必要があります：

```
skeleton->update(deltaTime);
skeleton->updateWorldTransform(spine::Physics_Update);
```

`deltaTime` は現在のフレームと最後のフレームの間の経過時間を秒単位で指定します。`spSkeleton_updateWorldTransform` の2番目のパラメータは物理演算を適用するかどうかを指定します。一般的には `spine::Physics_Update` をデフォルト値にするのが良いでしょう。

結果は各ボーンに保存され、以下のように構成されます:

* `a`、`b`、`c`、`d` は、ボーンの回転、スケール、シアーを符号化した2x2列のメジャー行列
* `worldX`、`worldY` は、ボーンのワールド座標を保管

`worldX` および `worldY` は、`skeleton->x` と `skeleton->y` によってオフセットされることに注意してください。これらの2つのフィールドは、ゲームエンジンのワールド座標系でスケルトンを配置するために使うことができます。

通常、ボーンのワールドトランスフォームは直接変更してはいけません。代わりに、`Skeleton::updateWorldTransform()` を呼び出すことで、常にスケルトン内のボーンのローカルトランスフォームから派生させる必要があります。ローカルトランスフォームは、プロシージャルに設定することができます。例えば、マウスカーソルを指すようにボーンの回転を設定したり、アニメーションを適用(下記参照)したり、その両方を同時に行うことができます。(プロシージャルな)アニメーションが適用されると、`Skeleton::updateWorldTransform()` が呼び出され、結果のワールドトランスフォームはローカルトランスフォームと、ボーンに適用されている全てのコンストレイントに基づいて再計算されます。

### 座標系の変換
他のエンティティや入力イベントからの座標が通常与えられる場所であるため、ワールド座標系でボーンを操作した方が簡単であることがよくあります。しかし、ワールドトランスフォームは直接操作されるべきではないので、ワールド座標系の計算に基づくボーンへの変更を、そのボーンのローカルトランスフォームに適用する必要があります。

spine-cppランタイムは、ボーンの2x2ワールドトランスフォーム行列から回転とスケールの情報を抽出し、位置と回転をローカル空間からワールド空間へ、またはその逆に変換する関数を提供します。これらの関数はすべて、ボーンのワールドトランスフォームが`Skeleton::updateWorldTransform()` を呼び出すことによって事前に計算されていることを前提としています:

```
Bone* bone = skeleton->findBone("mybone");

// ワールド空間のX軸に対するボーンの回転を度数で取得する
float rotationX = bone->getWorldRotationX();

// ワールド空間のY軸に対するボーンの回転を度単位で取得する
float rotationY = bone->getWorldRotationY();

// ワールド空間のX軸に対するボーンのスケールを取得する
float scaleX = bone->getWorldScaleX();

// ワールド空間のY軸に対するボーンのスケールを取得する
float scaleY = bone->getWorldScaleY();

// ワールド空間で与えられた位置を、ボーンのローカル空間に変換する
float localX = 0, localY = 0;
bone->worldToLocal(worldX, worldY, localX, localY);

// ボーンのローカル空間で与えられた位置を、ワールド空間に変換する
float worldX = 0, worldY = 0;
bone->localToWorld(localX, localY, worldX, worldY);

// ワールド空間で与えられた回転をボーンのローカル空間に変換する
float localRotationX = bone->worldToLocalRotation(bone)
```

> **注意:** ボーン（およびそのすべての子）のローカルトランスフォームへの変更は、次に`Skeleton::updateWorldTransform()`を呼び出した後に、ボーンのワールドトランスフォームに反映されます。

## ポジションの決定
デフォルトでは、スケルトンはゲームのワールド座標系の原点にあると仮定されます。ゲームのワールド座標系でスケルトンを配置するには、`x`および`y`プロパティを使用します:

```
// ワールド空間でゲームオブジェクトに追従するスケルトンを作成
skeleton->setX(myGameObject->worldX);
skeleton->setY(myGameObject->worldY);
```

> **注意:** スケルトンの `x` および `y` プロパティへの変更は、次に`Skeleton::updateWorldTransform()` を呼び出した後に、ボーンのワールドトランスフォームに反映されます。

## 反転
スケルトンは垂直または水平に反転させることができます。これにより、ある方向用に作成したアニメーションを反対方向に再利用したり、Y軸が下向きの座標系で作業することができます（SpineはデフォルトでY軸が上向きの座標系を想定しています）:

```
// x軸を中心に垂直に反転する
skeleton->setScaleX(-1);

// y軸を中心に水平反転しない
skeleton->setScaleY(-1);
```

> **注意:** スケルトンの `scaleX` と `scaleY` プロパティに対する変更は、次に`Skeleton::updateWorldTransform()`　を呼び出した後に、ボーンのワールドトランスフォームに反映されます。

## スキンの設定
Spineのスケルトンを作成したアーティストは、同じスケルトンに複数の[スキン](/spine-runtime-skins)を追加して、女性版と男性版など、視覚的なバリエーションを追加することができます。spine-cppランタイムはスキンを`Skin`インスタンスに格納します。

[ランタイムにおけるスキン](/spine-runtime-skins)は、どの[アタッチメント](/spine-basic-concepts#アタッチメント)をスケルトンのどの[スロット](/spine-basic-concepts#スロット)に入れるかを定義したマップです。すべてのスケルトンは少なくとも1つのスキンを持っており、どのアタッチメントがスケルトンのセットアップ・ポーズのどのスロットにあるのかを定義しています。追加されたスキンは、それらを識別するための名前を持ちます。

spine-cppでスケルトンにスキンを設定:

```
// 名前によってスキンを設定
skeleton->setSkin("my_skin_name");

// NULLを渡してデフォルトのセットアップポーズのスキンを設定
skeleton->setSkin(NULL);
```

> **注意:** スキンの設定は、以前に設定されたスキンやアタッチメントが考慮されます。[スキン設定の詳細](/spine-runtime-skins#Skin-changes)については、総合的なランタイムガイドを参照してください。

## アタッチメントの設定
spine-cppは、例えば武器を切り替えたりするために、スケルトンのスロットに直接アタッチメントを1つ設定することができます。アタッチメントは、まずアクティブなスキンで検索され、これが失敗した場合は、デフォルトのセットアップポーズスキンで検索されます:

```
// "hand"スロットに"sword"というアタッチメントをセットする
skeleton->setAttachment("hand", "sword");

// スロット"hand"のアタッチメントをクリアして、何も表示されないようにする
skeleton->setAttachment(skeleton, "hand", "");
```

### ティント
スケルトンのカラーを設定することで、スケルトン内のすべてのアタッチメントをティント(着色)することができます:

```
// すべてのアタッチメントを赤で着色し、スケルトンを半分だけ透明にする
skeleton->getColor().set(1, 0, 0, 0.5f);
```

> **注意:** spine-cppの色はRGBAで示され、各チャンネルの値は[0-1]の範囲になります。

スケルトンを描画するとき、レンダラーはスケルトン上のスロットの表示順序をたどり、各スロットに現在アクティブなアタッチメントを描画します。スケルトンのカラーに加えて、各スロットも実行時に操作可能なカラーを持っています:

```
Slot* slot = skeleton->findSlotByName("mySlot");
slot->getColor().set(1, 0, 1, 1);
```

なお、スロットカラーもアニメーションさせることができます。スロットカラーを手動で変更した後に、そのスロットカラーをキーにしたアニメーションを適用すると、手動での変更内容は上書きされることに注意してください。

# アニメーションの適用
Spineエディターでは、アーティストが一意の名前の[アニメーション](/spine-animating)を複数作成することができます。アニメーションとは、[タイムライン](/spine-api-reference#Timeline)の集合体です。各タイムラインは、ボーンやスケルトンのどのプロパティが、どのフレームでどのような値に変化するかを指定します。タイムラインには、時間経過によるボーンのトランスフォームを定義するタイムラインから、表示順序を変更するタイムラインまで、様々なタイプがあります。タイムラインはスケルトンデータの一部で、spine-cppの `SkeletonData` 内の `Animation` インスタンスに格納されています。

## Timeline API
spine-cppは、タイムラインを直接操作する必要が生じた場合に、[Timeline API](/spine-applying-animations#Timeline-API)を提供します。この低レベルの機能により、アーティストが定義したアニメーションがスケルトンに適用される方法を完全にカスタマイズすることができます。

## AnimationState API
ほとんどの場合、Timeline APIではなく[AnimationState API](/spine-applying-animations#AnimationState-API)を使用した方が良いでしょう。AnimationState APIは、アニメーションの時間経過による適用、アニメーションのキューイング、アニメーション間のミックス、複数のアニメーションの同時適用などのタスクを、低レベルのTimeline APIよりもかなり簡単に実行できます。AnimationState API は内部的には Timeline API を使用しており、ラッパーと見なすことができます。

spine-cppは `AnimationState` クラスでアニメーションの状態を表現します。スケルトンと同じように、`AnimationState` はゲームオブジェクトごとにインスタンス化されます。一般的には、ゲーム内のゲームオブジェクトごとに、1つの `Skeleton` と1つの `AnimationState` インスタンスを持つことになります。また `Skeleton` と同様に、`AnimationState` も(アニメーションとそのタイムラインが格納されている) `SkeletonData` と（ミックスタイムが格納されている）`AnimationStateData` を他のすべての `AnimationState` インスタンスと共有し、同じスケルトンデータをソースとすることができます。

### AnimationStateの作成
`AnimationState` インスタンスを作成するには:

```
AnimationState* animationState = new AnimationState(animationStateData);
```

この関数は、通常スケルトンデータのロードの際に作成される `AnimationStateData` を受け取り、デフォルトのミックスタイムや[クロスフェード](/spine-applying-animations#ミックスタイム)用の特定のアニメーション間のミックスタイムを定義します。

### トラックとキューイング
AnimationStateは、1つまたは複数の[トラック](/spine-applying-animations#トラック)を管理します。各トラックはアニメーションのリストで、トラックに追加された順番に再生します。これは[キューイング](/spine-applying-animations#キューイング)と呼ばれます。トラックは0から始まるインデックスを持っています。

以下のようにして、トラック上にアニメーションをキューすることができます:

```
// アニメーション"walk"をトラック0に、遅延(delay)なしで追加し、無限にループさせる
int track = 0;
bool loop = true;
float delay = 0;
animationState->addAnimation(track, "walk", loop, delay);
```

また、複数のアニメーションを一度にキューして、アニメーションシーケンスを作成することができます:

```
// walkをスタート (ループ有り)
animationState->addAnimation(0, "walk", true, 0);

// 3秒後にジャンプ
animationState->addAnimation(0, "jump", false, 3);

// ジャンプが完了したら、無限に待機(idle)を再生
animationState->addAnimation(0, "idle", true, 0);
```

また、トラック内にキューされているすべてのアニメーションをクリアすることができます:

```
// トラック0にキューされているアニメーションを全てクリアする
animationState->clearTrack(0);

// 全トラックでキューされているアニメーションを全てクリアする
animationState->clearTracks(animationState);
```

クリアして新しいアニメーションをトラックに追加する代わりに、`AnimationState::setAnimation()` を呼び出すこともできます。これはすべてのトラックをクリアしますが、クリアする前に最後に再生されたアニメーションが何であったかを記憶し、新たに設定されたアニメーションにクロスフェードします。これにより、あるアニメーション・シーケンスから次のアニメーション・シーケンスへスムーズに移行することができます。`AnimationState::setAnimation()` を呼び出した後に `AnimationState::addAnimation()` を呼び出すと、さらにアニメーションをトラックに追加することができます:

```
// 現在トラック0で再生されているものが何であれ、トラックをクリアして
// "shot"アニメーションにクロスフェードする。これはループしません(最後のパラメータで指定)
animationState->addAnimation(0, "shot", false, 0);

// 射撃の後、再び待機(idle)させる
animationState->addAnimation(0, "idle", true, 0);
```

アニメーションからスケルトンのセットアップポーズにクロスフェードするには、`AnimationState::setEmptyAnimation()`、`AnimationState::addEmptyAnimation()` を使います。前者は現在のトラックをクリアしてスケルトンにクロスフェードし、後者はトラック上のアニメーションシーケンスの一部としてセットアップポーズにクロスフェードをエンキューします。

```
// 現在トラック0で再生されているものが何であれ、トラックをクリアして
// セットアップポーズに0.5秒（ミックスタイム）でクロスフェードする
animationState->setEmptyAnimation(0, 0.5f);

// トラック0のアニメーションシーケンスの一部として、
// セットアップポーズに0.5秒間、クロスフェードを追加し、1秒間の遅延(delay)を設定する
animationState->addEmptyAnimation(0, 0.5f, 1)
```

シンプルなゲームでは、通常、1つのトラックだけ使用すれば十分に目的を達成できます。より複雑なゲームでは、例えば、射撃中に歩行アニメーションを同時に再生するなど、別々のトラックでアニメーションをキューイングすることもできます。ここでSpineの真価が発揮されます:

```
// トラック0に"walk"アニメーションを無限に適用する
animationState->setAnimation(0, "walk", true);

// トラック1に"shot"アニメーションを1回だけ適用する
animationState->setAnimation(1, "shot", false);
```

このように同時にアニメーションを適用すると、両方のアニメーションがキーにしているすべての値について、上位トラックのアニメーションが下位トラックのアニメーションを上書きしてしまうことに注意してください。つまり、アニメーションのオーサリング(組み合わせ)を行う場合、同時に再生する2つのアニメーションが、そのスケルトンで同じ値（同じボーン、アタッチメント、色など）をキーにしないことを確認してください。加算式アニメーションブレンディングであれば、同じスケルトンプロパティに影響を与える異なるトラック上のタイムラインの結果を足し算することができます。

[TrackEntry](/spine-applying-animations#TrackEntry)により、異なるトラックでのアニメーションのミキシングを制御することができます。

### トラックエントリ
AnimationStateのトラックでアニメーションをエンキューするたびに、対応する関数は`TrackEntry` インスタンスを返します。このトラックエントリにより、キューされたアニメーションや、同じトラックや他のトラック上のアニメーションとのミキシング挙動をさらにカスタマイズすることができます。完全なAPIは[TrackEntryのドキュメント](/spine-api-reference#TrackEntry)を参照してください。

例えば、`AnimationStateData` で定義された"walk"と"run"アニメーションのミックスタイムが、このゲームオブジェクトの現在の状況に対して高すぎると仮定してみましょう。このキューに入れられたアニメーションのために、"walk"と"run"のミックスタイムをアドホックに変更することができます:

```
// 無限に"walk"する
sanimationState->setAnimation(0, "walk", true);

// ある時点で、"run"アニメーションをキューに入れる。この特定の呼び出しを速くするために、
// `AnimationStateData`で定義された"walk"と"run"の間のミックスタイム(仮に0.5秒とします)
// を速くします(ここでは0.1秒に設定)。
TrackEntry* entry = animationState->addAnimation(0, "run", true, 0);
entry->setMixTime(0.1f);
```

`TrackEntry` を保持することで、時間の経過とともに変更することができます。`TrackEntry` は、そのトラックにアニメーションがキューイングされている間、有効です。アニメーションが完了すると、 `TrackEntry` は割り当て解除されます。それ以降のアクセスは無効となり、セグメンテーション違反が発生するでしょう。リスナーを登録すれば、アニメーションやトラックエントリが無効になったときに通知を受けることができます。

### イベント
AnimationStateは、キューイングされたアニメーションを再生しながらイベントを生成し、リスナーに以下の変更を通知します:

* アニメーションが**開始された(start)**。
* トラックをクリアするなどにより、アニメーションが**中断された(interrupt)**。
* アニメーションが**完了した(complete)**。※ループしている場合は複数回発生
* アニメーションが**終了した(end)**。※中断されたか、または完了しループされていない場合に発生。
* アニメーションとそれに対応する `TrackEntry` が**破棄された(dispose)**、且つ無効になった。
* [ユーザーが定義した**イベント(event)**](/spine-events)が発生した。

これらのイベントは、AnimationState、またはAnimationStateから返される個々の `TrackEntry` インスタンスに関数を登録することで、リッスンすることができます。

```
// イベントが発生したときに呼び出される関数を定義する
void callback (AnimationState* state, EventType type, TrackEntry* entry, Event* event) {
	const String& animationName = (entry && entry->getAnimation()) ? entry->getAnimation()->getName() : String("");

	switch (type) {
	case EventType_Start:
		printf("%d start: %s\n", entry->getTrackIndex(), animationName.buffer());
		break;
	case EventType_Interrupt:
		printf("%d interrupt: %s\n", entry->getTrackIndex(), animationName.buffer());
		break;
	case EventType_End:
		printf("%d end: %s\n", entry->getTrackIndex(), animationName.buffer());
		break;
	case EventType_Complete:
		printf("%d complete: %s\n", entry->getTrackIndex(), animationName.buffer());
		break;
	case EventType_Dispose:
		printf("%d dispose: %s\n", entry->getTrackIndex(), animationName.buffer());
		break;
	case EventType_Event:
		printf("%d event: %s, %s: %d, %f, %s\n", entry->getTrackIndex(), animationName.buffer(), event->getData().getName().buffer(), event->getIntValue(), event->getFloatValue(),
				event->getStringValue().buffer());
		break;
	}
	fflush(stdout);
}

// AnimationStateに関するリスナーとして関数を登録する。この関数は、 
// AnimationStateにキューされたすべてのアニメーションに対して呼び出されます
animationState->setListener(myListener);

// あるいは、エンキューされた特定のアニメーションのイベントのリスナーとしてこの関数を登録することもできます
TrackEntry* trackEntry = animationState->setAnimation(0, "walk", true);
trackEntry->setListener(myListener);
```

ユーザー定義イベントは、アニメーションの中で足音などを再生する時間をマークアップするのに最適な機能です。

新しいアニメーションの設定など、リスナー内で行われたAnimationStateの変更は、次に `AnimationState::apply` が呼び出されるまでスケルトンに適用されません。リスナー内で変更を即座に適用することができます:

```
void myListener(AnimationState* state, EventType type, TrackEntry* entry, Event* event) {
	if (somecondition) {
		state->setAnimation(0, "run", false);
		state->update(0);
		state->apply(skeleton);
	}
}
```

### AnimationStateを適用する
AnimationStateは、本質的に時間ベースです。状態を変化させるには、tickごとに更新する必要があり、最後の更新からの経過時間を秒単位で指定します:

```
state->update(deltaTimeInSeconds);
```

これにより、各トラックのアニメーションの再生を進めたり、クロスフェードを調整したり、登録したリスナーを呼び出したりすることができます。

AnimationStateを更新した後、それをスケルトンに適用して、そのボーンのローカルトランスフォーム、アタッチメント、スロットカラー、表示順序、その他アニメーションできるものを更新するには以下を行います:

```
state->apply(*skeleton);
```

スケルトンのポーズとアニメーションが完了したら、最後にボーンのワールドトランスフォームを更新して、レンダリングや物理演算の準備をします：

```
skeleton->update(deltaTime);
skeleton->updateWorldTransform();
```

# 全てをまとめた結果
ここでは、ロード、インスタンス化からアニメーションの適用まで、上記のすべてをまとめた簡単な例を示します（スクロールするとすべてのコードが表示されます）:

```
// 全スケルトンで共有されるセットアップポーズデータ
Atlas* atlas;
SkeletonData* skeletonData;
AnimationStateData* animationStateData;

// 5体のスケルトンインスタンスとそれらのAnimationState
Skeleton* skeleton[5];
AnimationState* animationState[5];
char* animationNames[] = { "walk", "run", "shot" };

void setup() {
	// アトラスのテクスチャを読み込めるようにエンジンをセットアップする、ウィンドウを作成する、など。
	engine_setup();

	// テクスチャアトラスのロード
	atlas = new Atlas("spineboy.atlas", MyEngineTextureLoader());
	if (atlas.getPages().size() == 0) {
		printf("Failed to load atlas");
		delete atlas;
		exit(0);
	}

	// スケルトンデータのロード
	SkeletonJson json(atlas);
	skeletonData = json.readSkeletonDataFile("spineboy.json");
	if (!skeletonData) {
		printf("Failed to load skeleton data");
		delete atlas;
		exit(0);
	}

	// 各ミックスタイムの設定
	animationStateData = new AnimationStateData(skeletonData);
	animationStateData->setDefaultMix(0.5f);
	animationStateDAta->setMix("walk", "run", 0.2f);
	animationStateData->setMix("walk", "shot", 0.1f);
}

void mainLoop() {
	// 5つのゲームオブジェクトを表す5体のスケルトンインスタンスと
	// AnimationStateを作成。
	for (int i = 0; i < 5; i++) {
		// スケルトンを作成し、ランダムな位置に配置する
		Skeleton* skeleton = new Skeleton(skeletonData);
		skeleton->setX(random(0, 200));
		skeleton->setY(random(0, 200));

		// AnimationStateを作成し、ランダムなアニメーションをループさせながらエンキューする
		AnimationState *animationState = new AnimationState(animationStateData);
		animationState->setAnimation(0, animationNames[random(0, 3)], true);
	}

	while (engine_gameIsRunning()) {
		engine_clearScreen();

		// ゲームオブジェクトのアップデート
		for (int i = 0; i < 5; i++) {
			Skeleton* skeleton = skeletons[i];
			AnimationState* animationState = animationStates[i];

			// まず、AinmationStateをデルタタイムで更新する
			animationState->update(engine_getDeltaTime());

			// 次に、スケルトンにそのAinmationStateを適用する
			animationState->apply(skeleton);

			// 物理演算のためにスケルトンのフレーム時間を更新する
         	skeleton->update(engine_getDeltaTime());

			// レンダリングのためのワールドトランスフォームを計算する
			skeleton->updateWorldTransform();

			// スケルトンのレンダリングをエンジンに引き継ぐ
			engine_drawSkeleton(skeleton);
		}
	}

	// インスタンスデータを破棄する。通常は、ゲームオブジェクトを
	// 破棄するときに行います。
	for (int i = 0; i < 5) {
		delete skeletons[i];
		delete animationStates[i];
	}
}

void dispose() {
	// 共有リソースをすべて破棄する
	delete atlas;
	delete skeletonData;
	delete animationStateData;
}

int main(int argc, char* argv) {
	setup();
	mainLoop();
	dispose();
}
```

セットアップポーズデータ(`Atlas`, `SkeletonData`, `AnimationStateData`) とインスタンスデータ (`Skeleton`, `AnimationState`)の区別とそのライフタイムの違いに注意してください。

# メモリ管理
私たちは spine-cpp のメモリ管理をできるだけ単純化するように努めました。`new` でアロケートされたクラスや構造体は、対応する `delete` で解放される必要があります。クラスインスタンスの寿命は、それがどのようなタイプのクラスインスタンスであるかに依存します。一般的なルールは以下の通りです:

* ゲームまたはレベル起動時にインスタンスデータ(`Atlas`, `SkeletonData`, `AnimationStateData`)と共有するセットアップポーズデータを作成し、ゲームまたはレベルの終了時に破棄します。
* 対応するゲームオブジェクトの生成時にインスタンスデータ(`Skeleton`, `AnimationState`)を作成し、対応するゲームオブジェクトの破棄時に破棄します。

トラックエントリ(`TrackEntry`)は、AnimationStateの関数 (`AnimationState::setAnimation()`, `AnimationState::addAnimation()`, `AnimationState::setEmptyAnimation()`, `AnimationState::addEmptyAnimation()`)が呼び出されてから`EventType_dispose`イベントがリスナーに送られるまで有効です。このイベントの後にトラックエントリにアクセスすると、セグメンテーション違反が発生する可能性があります。

構造体を作成する際、他の構造体を参照として渡すことがよくあります。参照元の構造体が、参照先の構造体を破棄することはありません。例えば、`Skeleton`は`SkeletonData`を参照し、その`spSkeletonData`が`Atlas`を参照しています。

* `Skeleton` を破棄しても、`SkeletonData` や `Atlas` は破棄されません。これは、`SkeletonData` は他の `Skeleton` インスタンスと共有されている可能性が高いためです。
* `SkeletonData` を破棄しても、`Atlas` は破棄されません。これは、アトラスに複数のスケルトンの画像が含まれている場合など、`Atlas` が他の `SkeletonData` インスタンスと共有されることがあるためです。

カスタムアロケーターを使用する場合、独自の `SpineExtension` を実装することで、Spineのアロケーションストラテジー(割り当て戦略)を上書きできます。カスタム`SpineExtension` は `DefaultSpineExtension` から派生して、`_alloc`、`_calloc`、`_realloc`、`_free`(`_readFile`の実装を継承)をオーバーライドする必要があります。その後、プログラム起動時に `spine::SpineExtension::setInstance()` を呼び出すことで、拡張子を設定することができます。また、Spineランタイムエンジンとの連携を行わない場合は、`spine::getDefaultExtension()` メソッドを実装して、エンジンのメモリ管理やファイル管理と互換性のある拡張子をSpineに提供する必要があります。

また、Spineには簡単なメモリーリーク検出機能があり、`spine/Debug.h` に`DebugExtension` という `SpineExtension` のラッパークラスが用意されています。`DebugExtension` で他のエクステンションをラップすると、Spineオブジェクトを以下のように割り当てた場合、ファイルの場所と行番号とともに、割り当てを追跡できるようになります:

```
Skeleton* skeleton = new (__FILE__, __LINE__) Skeleton(skeletonData);
```

`__FILE__` と `__LINE__` 引数は、デバッグ拡張モジュールがどこでアロケーションが発生したかを記録するために使用されます。プログラムが終了するとき、デバッグ拡張が`stdout`(標準出力)にレポートを出力するようにすることができます。

```
#include <spine/Extension.h>
#include <spine/Debug.h>

static DebugExtension *debugExtension = NULL;

// これは、Spineが最初の拡張インスタンスを取得するために使用されます。
SpineExtension* spine::getDefaultExtension() {
	// メモリ管理に標準的なmallocを使用するDefaultSpineExtensionを返し、
	// それをdebugExtensionでラップします。
	debugExtension = new DebugExtension(new DefaultSpineExtension());
	return debugExtension;
}

int main (int argc, char** argv) {
	... your app code allocating Spine objects via `new (__FILE__, __LINE__) SpineClassName()` and deallocating via `delete instance` ...

	debugExtension->reportLeaks();
}

```

# spine-cppをエンジンに統合する
## ソースの統合
spine-cppは、ランタイムGitリポジトリの[spine-cpp/spine-cpp](/git/spine-runtimes/tree/spine-cpp/spine-cpp)フォルダにあるC++ヘッダーと実装のファイル群です。ソースをプロジェクトにコピーするか、CMakeの `FetchContent` を使ってください。

### ソースをコピーする場合

1. まず[Spineランタイムのリポジトリ](https://github.com/EsotericSoftware/spine-runtimes)をクローンします。使用しているSpineエディターのバージョンに対応するブランチを使用してください。
2. [spine-cpp/spine-cpp/src/spine](/git/spine-runtimes/tree/spine-cpp/spine-cpp/src/spine)フォルダ内のファイルをご自身のビルドに含めます。
3. [spine-cpp/spine-cpp/include](/git/spine-runtimes/tree/spine-cpp/spine-cpp/include/spine)フォルダをご自身のヘッダー検索パスに追加します。

### CMakeのFetchContentを使用する場合
Spineバージョン4.2以降では、CMakeの `FetchContent` 機能を使うことで、以下の `CMakeLists.txt` ファイルの例のようにspine-cppランタイムを簡単にプロジェクトに統合することができます：

```
cmake_minimum_required(VERSION 3.14)
project(MyProject C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(FETCHCONTENT_QUIET NO)

# spine-runtimesリポジトリを取得し、spine-cppライブラリを利用可能にする
include(FetchContent)
FetchContent_Declare(
  spine-runtimes
  GIT_REPOSITORY https://github.com/esotericsoftware/spine-runtimes.git
  GIT_TAG 4.2
  GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(spine-runtimes)
FetchContent_GetProperties(spine-runtimes)
if(NOT spine-runtimes_POPULATED)
    FetchContent_Populate(spine-runtimes)
endif()
add_subdirectory(${spine-runtimes_SOURCE_DIR}/spine-c ${CMAKE_BINARY_DIR}/spine-runtimes)

# シンプルなC++実行ファイルを作成
file(GLOB SOURCES "src/*.cpp")
add_executable(MyExecutable ${SOURCES})
target_include_directories(MyExecutable PRIVATE src/)

# spine-cpp ライブラリをリンクする
target_link_libraries(MyExecutable spine-cpp)
```

## メモリとファイル入出力の実装
プロジェクトをコンパイルすると、spine-cppランタイムが実装を期待する関数に対してリンカエラーが発生することがあります。例えば、Clangでコンパイルした場合に以下のようなエラーになる場合があります:

```
Undefined symbols for architecture x86_64:
  "spine::getDefaultExtension()", referenced from:
      spine::SpineExtension::getInstance() in libspine-cpp.a(Extension.cpp.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```
リンカはSpineExtensionを返す関数を見つけられませんでした。spine-cppランタイムは、お使いのエンジンが提供するAPIを使用して `SpineExtension` から派生したクラスを実装することを期待します。この拡張は[Extension.h](/git/spine-runtimes/blob/spine-cpp/spine-cpp/include/spine/Extension.h)で定義されています。

`malloc`、`free`、`FILE` ベースのファイル入出力の使用に満足している場合は、`DefaultSpineExtension` を使用して、このように不足している関数を実装することができます：

```
#include <spine/Extension.h>

spine::SpineExtension *spine::getDefaultExtension() {
	return new spine::DefaultSpineExtension();
}
```

それ以外の場合は、`SpineExtension` または `DefaultSpineExtension` から派生して、`_malloc`、`_calloc`、`_realloc`, `_free`、`_readFile` メソッドをオーバーライドします。

### TextureLoaderの実装
spine-cppの `Atlas` クラスは、一つのアトラスページに対してエンジン固有のテクスチャ表現をロードして作成するために、`TextureLoader` インスタンスを渡されることを想定しています。[`TextureLoaderクラス`](/git/spine-runtimes/blob/spine-cpp/spine-cpp/src/spine/TextureLoader.h) は、パスを与えられたアトラスページのメソッドをロードする `load`、そしてテクスチャを破棄する `unload` の2つのメソッドを持っています。

`load` 関数は、テクスチャを `AtlasPage::texture` に代入してアトラスページに保存することができます。これにより、後でアトラスページの領域を介してアタッチメントが参照するテクスチャを取得するのが簡単になります。

`load` 関数の `path` パラメータはページ画像ファイルへのパスで、 `Atlas` コンストラクタに渡された `.atlas` ファイルパスからの相対パスか、メモリからアトラスをロードする2番目の `Atlas` コンストラクタの `dir` パラメータからの相対パスです。

`load` 関数 の`path` パラメータはページ画像ファイルのパスで、`Atlas`　コンストラクタに渡された　`.atlas`　ファイルのパスからの相対パス、またはメモリからアトラスをロードする2番目の　`Atlas`　コンストラクタの　`dir`　パラメータからの相対パスとなります。

説明のために、お使いのエンジンがテクスチャを扱うために以下のようなAPIを提供しているとします:

```
struct Texture {
	// ... OpenGL handle, image data, whatever ...
	int width;
	int height;
};

Texture* engine_loadTexture(const char* file);
void engine_disposeTexture(Texture* texture);
```

`TextureLoader`の実装は、次のように簡単です:

```
#include <spine/TextureLoader.h>

class MyTextureLoader: public TextureLoader {
	public:
		TextureLoader() { }

        virtual ~TextureLoader() { }

		// アトラスがページのテクスチャをロードするときに呼び出されます。
        virtual void load(AtlasPage& page, const String& path) {
			Texture* texture = engine_loadTexture(path);

			// テクスチャのロードに失敗した場合は、単にリターンします。
			if (!texture) return;

			// TextureをrendererObjectに格納し、後でレンダリングのために
			// それを取得できるようにします。
			page.texture = texture;

		}

		// アトラスが破棄され、それ自身がアトラスページを破棄するときに呼ばれます。
        virtual void unload(void* texture) {
			// textureパラメータは page->setRendererObject() でページに保存したテクスチャです。
			engine_disposeTexture(texture);
		}
}
```

出来上がったTextureLoaderは、2つの `Atlas` コンストラクタのいずれかに渡すことができます。

## レンダリングの実装
Spineスケルトンのレンダリングでは、現在アクティブなすべての領域およびメッシュアタッチメントを、現在の[表示順序](/spine-basic-concepts#スロット)でレンダリングします。表示順序は、スケルトンの[スロットの配列](/git/spine-runtimes/blob/spine-c/spine-c/include/spine/Skeleton.h#L54)として定義されます。さらに、クリッピングアタッチメントが、領域およびメッシュアタッチメントをクリップすることがあります。

spine-cppが提供している `SkeletonRenderer` クラスは、スケルトンのアクティブなアタッチメントから、テクスチャ、頂点カラー、ブレンドが適用された三角メッシュを簡単に生成することができます。

説明のために、お使いのエンジンに以下のようなAPIがあると想定します:

```
//  UVを伴う単一の頂点
struct Vertex {
	// x/y 平面上の位置
	float x, y;

	// UV座標
	float u, v;

	// パックされたRGBAカラー
   uint32_t color;
};

enum BlendMode {
	// これらがOpenGLのソース/デスティネーションブレンドモードにどのように変換されるかについては、
	// こちらをご覧ください。　http://esotericsoftware.com/git/spine-runtimes/blob/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BlendMode.java#L37
	BLEND_NORMAL,
	BLEND_ADDITIVE,
	BLEND_MULTIPLY,
	BLEND_SCREEN,
}

// 与えられたメッシュを描画する。
// - vertices はVertex構造体の配列へのポインタです。
// - indices は、インデックスの配列へのポインタです。3の連続するインデックスは三角形を形成します。
// - numIndicesは、インデックスの数です。三角形の頂点が3つであることから、3で割り切れる必要があります。
// - texture は、使用するテクスチャです。
// - blendMode は、使用するブレンドモードです。
void engine_drawMesh(Vertex* vertices, unsigned short* indices, size_t numIndices, Texture* texture, BlendMode blendmode);
```

そして、レンダリング処理は次のように実装することができます:

```
// 頂点を一時的に保管するコンテナ
spine::Vector<Vertex> vertices;
// 単一のSkeletonRendererインスタンス (レンダリングがシングルスレッドで実行されると仮定)
SkeletonRenderer skeletonRenderer;

void drawSkeleton(Skeleton &skeleton) {
   RenderCommand *command = skeletonRenderer.render(skeleton);
   while (command) {
      Vertex vertex;
      float *positions = command->positions;
      float *uvs = command->uvs;
      uint32_t *colors = command->colors;
      uint16_t *indices = command->indices;
      Texture *texture = (Texture *)command->texture;      
      for (int i = 0, j = 0, n = command->numVertices * 2; i < n; ++i, j += 2) {
         vertex.x = positions[j];
         vertex.y = positions[j + 1];
         vertex.u = uvs[j];
         vertex.v = uvs[j + 1];
         vertex.color = colors[i];
         vertices->add(vertex);
      }
      BlendMode blendMode = command->blendMode; // Spineのブレンドモードとエンジンのブレンドモードが同じ
      engine_drawMesh(vertices->buffer(), command->indices, command->numIndices, texture, blendMode)
      vertices.clear()
      command = command->next;
   } 
}
```

`SkeletonRenderer::render()` は、`RenderCommand` インスタンスのリンクリストを返します。各 `RenderCommand` は、頂点、インデックス、ブレンドモード、テクスチャで構成される1つのメッシュを表します。お使いのエンジンで `RenderCommand` をレンダリングするには、頂点を必要なフォーマットに変換し、ブレンドモードとテクスチャを設定し、トランスフォームした頂点とインデックスを描画します。これにより、バッチ処理を自分で実装することなく、エンジンの描画呼び出し回数を最小限に抑えることができます。`RenderCommand::next` を使って繰り返しながら、残りのレンダーコマンドを描画します。

`SkeletonRenderer` は、ブレンドモードとテクスチャが同じであれば、複数のアタッチメントのメッシュを1つの `RenderCommand` にバッチします。

上記の実装は、2色ティントを除くすべてのSpine機能をサポートしています。OpenGLを使用した実装例については[spine-glfw](/git/spine-runtimes/spine-glfw/src/spine-glfw.cpp)ランタイムを参照してください。