# Spine iOSランタイム　ドキュメント

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

# はじめに
Spine iOSランタイムは[spine-cpp](/spine-cpp)の薄いラッパーを使って実装されています。`UIKit` と `SwiftUI` の両方を使って実行できます。`Swift` と `Objective-C` の両方がサポートされています。

レンダリングには[Metal](https://developer.apple.com/metal/)を使用しており、ティントブラックを除くすべてのSpine機能をサポートしています。

## インストール方法
Spine iOS は iOS 13 以降でサポートされています。プロジェクトでSpine iOSを使用するには、[Swift Package Manager](https://www.swift.org/documentation/package-manager/)または[CocoaPods](https://cocoapods.org)を使用してインストールすることができます。

spine-runtimesリポジトリのブランチの `major.minor` バージョンが、エクスポートする Spineエディターの `major.minor` バージョンと一致していることを確認してください。詳しくは「[バージョンの同期](/spine-versioning#バージョンの同期)」を参照してください。

### Swift Package Manager

プロジェクトにSpine iOS SPMパッケージを追加するには:

1.	Xcodeでご自身のプロジェクトを開いてください。
2.	Project Settingsに移動します: Project Navigatorでプロジェクトをクリックし、ターゲットの右上にあるプロジェクトを選択します。
3.	Swift Packagesパッケージを選択します: `Package Dependencies` タブをクリックします。
4.	パッケージを追加: `+` をクリックして検索欄に `git@github.com:EsotericSoftware/spine-runtimes.git` を入力します。
5.	依存関係のルール: `Commit` を選択し、サポートしたい `major.minor` ブランチの最新の完全なコミットハッシュを入力します。
6.	終了: Next をクリックし、Xcodeがパッケージを解決した後、Finish をクリックします。

また、C++サポートを有効にする必要があります：

1. Project Settingsに移動します: アプリのメインターゲットをクリックします。
2. `Built Settings` タブを開きます: `C++ and Objective-C Interoperability` を探します。
3. `C++ / Objective-C++` を選択します。

### CocoaPods

バージョン管理方法の性質上、Spine iOSは公開されているCocoaPodsインデックスには含まれていません。ご自身の`Podfile` に追加するには、以下のように `.podspec` ファイルへリンクさせる必要があります。その際、正しい`major.minor`を使用してください。

```python
# 次の行のコメントを外して、プロジェクトのグローバル・プラットフォームを定義します。
platform :ios, '13.0'

target 'Spine iOS Example' do
  # ダイナミック・フレームワークを使いたくない場合は、次の行をコメントします。
  use_frameworks!

  pod 'Spine', :podspec => 'https://raw.githubusercontent.com/EsotericSoftware/spine-runtimes/4.2/Spine.podspec'
  pod 'SpineCppLite', :podspec => 'https://raw.githubusercontent.com/EsotericSoftware/spine-runtimes/4.2/SpineCppLite.podspec'
  pod 'SpineShadersStructs', :podspec => 'https://raw.githubusercontent.com/EsotericSoftware/spine-runtimes/4.2/SpineShadersStructs.podspec'
end
```

### 使用方法

どちらの場合も、Swiftファイルで `Spine` をインポートすることができます：

```Swift
import Spine
```

## サンプル
Spine iOSランタイムには、利用できる機能セットを実演しているサンプルがいくつか含まれています。

サンプルプロジェクトを実行するには:

1. お使いのMacに[Xcode](https://developer.apple.com/xcode/)をインストールします
2. spine-runtimesリポジトリをクローンします: `git clone https://github.com/esotericsoftware/spine-runtimes`
3. Xcodeで `spine-runtimes/spine-ios/Example/Spine iOS Example.xcodeproj` を開きます

代わりに、`spine-runtimes/spine-ios/Example - Cocoapods/Spine iOS Example.xcodeproj` を開いて `CocoaPods` を使用してSpine iOSがどのようにインポートされるかを確認することもできます。

以下のすべてのサンプルは `SwiftUI` のプレビューをサポートしており、Xcode上でキャンバスにレンダリングすることができます。

サンプルプロジェクトには以下のサンプルが含まれています：

* [`SimpleAnimation.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/SimpleAnimation.swift): エクスポートしたSpineスケルトンを読み込み、ビューに表示し、特定のアニメーションを再生する `SpineView` と `SpineController` の基本的な使い方を実演しています。
* [`PlayPauseAnimation.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/PlayPauseAnimation.swift): アニメーションを一時停止して再開する方法を実演しています。
* [`AnimationStateEvents.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/AnimationStateEvents.swift): スロットの色を設定する方法、複数のアニメーションをキューに入れる方法、AnimationStateイベントをリッスンする方法を実演しています。
* [`DebugRendering.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/DebugRendering.swift): `SpineController` の`onAfterPaint` コールバックを介して、レンダリングされたスケルトンの上にカスタム描画を実行する方法を実演しています。
* [`DressUp.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/DressUp.swift): Spineのスキン機能と、キャラクター作成UIで使用するためにスケルトンをサムネイルにレンダリングする方法を実演しています。
* [`IKFollowing.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/IKFollowing.swift): スケルトンのボーンをタッチ入力でドラッグする方法を実演しています。
* [`DisableRendering.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/DisableRendering.swift): `SpineView` が画面外に移動したときにレンダリングを無効にする方法を実演しています。これはCPU/GPUリソースを維持する必要がある場合に重要です。
* [`SimpleAnimationViewController.m`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/SimpleAnimationViewController.m): `UIKit` と `Objective-C` で `Spine iOS` を使用する方法を示します。

## Spine iOSランタイムのアップデート
プロジェクトのSine iOSランタイムをアップデートする前に、[Spineエディターとランタイムのバージョン管理に関するガイド](/spine-runtime-architecture#バージョン)を参照してください。

CocoaPodsについては、正しい `major.minor` ブランチにリンクしてください。

`SPM`の場合は、正しい `major.minor` ブランチから正しいコミットハッシュを選択してください。

> **注意:** `Spine iOS` パッケージの `major.minor` バージョンを変更した場合、使用しているSpineスケルトンを同じ `major.minor` バージョンのSpineエディターを使って再エクスポートする必要があることに注意してください！

# Spine iOSを使用する
Spine iOS ランタイムは、Spineで作成されたアニメーションのロード、再生、操作をサポートする汎用[spine-cpp](/spine-cpp)の慣用的なラッパーです。Spine iOSランタイムは、spine-cpp API のほとんどすべてを慣用的なSwiftとして公開し、Spineスケルトンを簡単に表示、操作するためのSwiftUIとUIKit固有のクラスを提供します。

Spine iOSランタイムは、ティントブラックを除くすべてのSpineの機能をサポートしています。
 
## アセットのマネージメント
### Spine iOS用にエクスポートする
![](/img/spine-runtimes-guide/spine-ue4/export.png)
以下の実行方法については、Spineユーザーガイド内で紹介されています :

1. [スケルトン＆アニメーションデータのエクスポート](/spine-export)
2. [スケルトンの画像を含むテクスチャアトラスのエクスポート](/spine-texture-packer)

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

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

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

> **補足**: JSONエクスポートよりもバイナリ形式でのスケルトンエクスポートの方がサイズが小さく、読み込みが速いので、基本的にはそちらを選択したほうが良いでしょう。

これらのファイルを、`Atlas`、`SkeletonData`、`SkeletonDrawable`、`SpineView`などのSpine iOSクラスを使って読み込むことができます。

> **注意**: 乗算済みアルファではないアセットを使用する場合は、アプリケーションターゲットのビルド設定で、`Compress PNG Files` と `Remove Text Metadata From PNG Files` を無効にする必要があるので注意してください。

### Spineアセットの更新
開発中にスケルトンデータやテクスチャアトラスファイルを更新したい時は、単純にSpineエディターから再エクスポートを行なって、Xcodeプロジェクト内の既存のファイル(`.json`、`.skel`、`.atlas`、`.png`)を置き換えるだけで簡単にこれらのソースファイルを更新できます。

その際、Spine iOSの`major.minor`バージョンとエクスポートを行ったSpineエディターの`major.minor`が一致していることを確認してください。詳しくは「[バージョンの同期](/spine-versioning#バージョンの同期)」を参照してください。

## コアクラス
Spine iOSのAPIは汎用[spine-cpp](/spine-cpp)ランタイムの上に構築されており、プラットフォームに依存しないコアクラスとSpineスケルトンのロード、クエリ、変更、アニメーションを行うアルゴリズムを提供します。コアクラスは、Swiftのイディオムクラスとして公開されます。

ここではSpine iOSを使用する際によく見ることになる最も重要なコアクラスについてのみ簡単に説明しています。Spineランタイムのアーキテクチャ、コアクラス、APIの使用法の詳細については、[Spineランタイムガイド](/spine-runtimes-guide)を参照してください。

[`Atlas`](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated.swift) クラスは、`.atlas` ファイルとそれに対応する `.png` 画像ファイルからロードしたデータを保管します。

[`SkeletonData`](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated.swift) クラスは、`.json` または `.skel` ファイルからロードされたデータを保管します。このスケルトンデータには、ボーン階層、スロット、アタッチメント、コンストレイント、スキン、アニメーションに関する情報が含まれます。`SkeletonData` インスタンスは、通常、それが表すスケルトンで使用されるイメージをソースとする `Atlas`(アトラス) も一緒に提供することによってロードされます。これは、`Skeleton` インスタンスを作成するための設計図として機能します。複数のスケルトンを同じアトラスとスケルトンデータからインスタンス化し、ロードされたデータを共有することで、ロード時間と実行時のメモリ消費を最小限に抑えることができます。

[`Skeleton`](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated.swift) クラスは、`SkeletonData` インスタンスから作成されたスケルトンのインスタンスを格納します。スケルトンは現在のポーズを保管します。つまり、ボーンの位置、スロット、アタッチメント、アクティブなスキンの現在の構成を保管します。現在のポーズは、手動でボーンのトランスフォームを変更するか、より一般的には、`AnimationState` を介してアニメーションを適用することで計算されます。

[`AnimationState`](/git/spine-runtimes/spine-ios/Sources/Spine/AnimationStateWrapper.swift) クラスは、 スケルトンに適用する(単数または複数の)アニメーションを追跡し、最後のレンダリングフレームと現在のレンダリングフレームの間の経過時間に基づいてそれらのアニメーションを進め、ミックスを行い、スケルトンインスタンスにアニメーションを適用して現在のポーズを設定します。`AnimationState` は [`AnimationStateData`](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated.swift) インスタンスに問い合わせ(処理要求)をして、アニメーション間のミキシング時間を取得します。特定のアニメーション間に使用するミキシング時間が無ければデフォルトミックスタイムを取得します。

Spine iOSランタイムはこれらのコアクラスの上に構築されています。

## SpineView / SpineUIView
![/img/spine-runtimes-guide/spine-ios/simple-animation.png](/img/spine-runtimes-guide/spine-ios/simple-animation.png)

`SpineView` struct は `SpineUIView` の周りの `UIViewRepresentable` なので、後者は`SwiftUI` プロジェクトで使用できます。`SpineUIView` は[MTKView](https://developer.apple.com/documentation/metalkit/mtkview)のサブクラスです。

以降、どちらかを参照するときは `SpineView` を使用します。

[`SpineView`](/git/spine-runtimes/spine-ios/Sources/Spine/SpineView.swift) は Spineのスケルトンをロードして表示する役割を果たします。最低限、ビューはスケルトンとアトラスファイルをどこからロードするかを知る必要があり、アニメーションの設定やスケルトンのスキンの変更など、ウィジェットの状態を変更する役割を持つ `SpineController` インスタンスを受け取ることができます。

`SpineController` は `ObservableObject` で、`@State` 変数内に保持されます。最も単純なケースでは、`SpineView` は以下のように他のビュー `body` の中でインスタンス化できます：

```Swift
@StateObject
var controller = SpineController(
    onInitialized: { controller in
        controller.animationState.setAnimationByName(
            trackIndex: 0,
            animationName: "walk",
            loop: true
        )
    }
)

var body: some View {
    SpineView(
        from: .bundle(atlasFileName: "spineboy.atlas", skeletonFileName: "spineboy-pro.skel"),
        controller: controller,
        mode: .fit,
        alignment: .center
    )
}
```

インスタンス化すると、`SpineView` は指定されたファイルを非同期でロードし、そこから基礎となるコアクラスのインスタンス、つまり `Atlas`、`SkeletonData`、`Skeleton`、`AnimationStateData`、`AnimationState` のインスタンスを構築します。

ロードが完了すると、`SpineController` の `onInitialized` が呼び出され、1つ以上のアニメーションの設定、ボーン階層の操作、スケルトンのスキンの変更など、ウィジェットの状態を変更できるようになります。以下の `SpineController` のセクションを参照してください。

`SpineView` クラスは、異なるソースからスケルトンとアトラスファイルをロードするために、最初のパラメーターとして `SpineViewSource` 列挙型(enum)を取ります：

* `SpineViewSource.bundle` は、メインバンドルまたは指定されたバンドルからファイルをロードします。
* `SpineViewSource.file` は、ファイルシステムからファイルをロードします。
* `SpineViewSource.http` は URL からファイルをロードします。
* `SpineViewSource.drawable()` は、`SkeletonDrawable` からビューを構築します。これは、スケルトンデータをプリロード、キャッシュ、および/または `SpineView` インスタンス間で共有する場合に便利です。以下の「スケルトンデータのプリロードと共有」のセクションを参照してください。

さらに、`SpineView` にはオプションの引数があり、Spineのスケルトンをビュー内でどのようにフィットさせ、どのように整列させるか、また、ビューのサイズをどのように設定するかを定義することができます。

* `mode ` : `SpineUIView` 内でのスケルトンのフィット方法。デフォルトは `.fit` です。
* `alignment` : `SpineUIView`内でスケルトンをどのように整列させるかを指定します。デフォルトは `.center` です。
* `boundsProvider` : これはフィットと整列を計算するときにスケルトンに使用されるバウンディングボックスのピクセルサイズを計算するために使用されます。デフォルトでは、スケルトンのセットアップポーズのバウンディングボックスが使用されます。詳細は、[`SetupPoseBounds`](/git/spine-runtimes/spine-ios/Sources/Spine/BoundsProvider.swift)、[`RawBounds`](/git/spine-runtimes/spine-ios/Sources/Spine/BoundsProvider.swift)、[`SkinAndAnimationBounds`](/git/spine-runtimes/spine-ios/Sources/Spine/BoundsProvider.swift)のクラスドキュメントを参照してください。
* `backgroundColor`: ビューの背景色。デフォルトでは `UIColor.clear` が使用されます。

`SpineView` には、レンダリングを無効にするオプションのバインディングパラメータ`isRendering` があります。詳細については、[`DisableRendering.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/DisableRendering.swift) の例を参照してください。

## SpineController
[`SpineController`](/git/spine-runtimes/spine-ios/Sources/Spine/SpineController.swift) は、`SpineView` のスケルトンのアニメーションを制御します。コントローラーは、コンストラクタの引数としてオプションのコールバックセットを提供します。これは `SpineView` のライフタイム中に特定のタイミングで呼び出されます。

コントローラは、`Atlas`、`SkeletonData`、`Skeleton`、`AnimationState` などの Spineランタイム API オブジェクトを返すゲッターを通して、スケルトンの状態を公開します。詳細については、[Spineランタイムガイド](/spine-runtimes-guide)および[クラスのドキュメント](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated+Extensions.swift)を参照してください。

`SpineView` を初期化すると、コントローラーの `onInitialized()` コールバックメソッドが呼び出されます。このメソッドを使用して、再生するアニメーションを設定したり、スケルトンのスキンを設定したりすることができます。

初期化が完了すると、`SpineView` は画面のリフレッシュレートで連続的にレンダリングされます。各フレームで `AnimationState` が現在キューに入っているアニメーションに基づいて更新され、`Skeleton` に適用されます。

次に、オプションの `onBeforeUpdateWorldTransforms()` コールバックが呼び出され、`Skeleton.updateWorldTransform()` を使って現在のポーズが計算される前にスケルトンを変更することができます。

現在のポーズが計算された後、オプションの `onAfterUpdateWorldTransforms()` コールバックが呼び出され、スケルトンがレンダリングされる前に現在のポーズをさらに修正することができます。手動でボーンの位置を変更したいならばここが適切です。

`SpineView` によってスケルトンがレンダリングされる前に、オプションの `onBeforePaint()` コールバックが呼び出されます。これにより、ビュー階層でスケルトンの後ろにあるべき背景やその他のオブジェクトをレンダリングすることができます。

`SpineWidget` が現在のスケルトンのポーズをレンダリングした後、オプションの `onAfterPaint()` コールバックが呼び出されます。

デフォルトでは、ビューはスケルトンを毎フレーム更新してレンダリングします。`SpineController.pause()` メソッドを使用すると、スケルトンの更新とレンダリングを一時停止できます。`SpineController.resume()` メソッドで、スケルトンの更新とレンダリングを再開できます。`SpineController.isPlaying` プロパティは、現在の再生状態を報告します。詳しくはサンプル [`AnimationStateEvents.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/AnimationStateEvents.swift) をご覧ください。

## SkeletonDrawableWrapper / SkeletonDrawable
`SkeletonDrawableWrapper` は `SkeletonDrawable` を保持し、 `Skeleton` とそれに関連する `AnimationState` の読み込み、保存、更新、レンダリングを一つの使いやすいクラスにまとめます。`SpineView` は `SkeletonDrawableWrapper` のインスタンスを介して、表示するスケルトンの状態をカプセル化します。

ファイルアセットから `SkeletonDrawableWrapper` を作成するには、`fromBundle()`、`fromFile()`、`fromHttp()` メソッドを使用します。複数の `SkeletonDrawableWrapper` インスタンス間で `Atlas` と `SkeletonData` を共有するには、同じアトラスとスケルトンデータを各インスタンスに渡し、コンストラクタでドローアブルをインスタンス化します。

`SkeletonDrawableWrapper` は `SkeletonDrawable`、`Skeleton`、`AnimationState`、`AnimationStateWrapper` を公開して、スケルトンのクエリ、変更、アニメーションを行います。また、スケルトンとアニメーション状態を構築するための `Atlas` と `SkeletonData` も公開しています。

スケルトンをアニメーションさせるには、`AnimationState.setAnimation()` や `AnimationState.addAnimation()` などの `AnimationState` API を使って、1つ以上のトラックにアニメーションをキューします。

アニメーションの状態を更新し、スケルトンに適用し、現在のスケルトンのポーズを更新するには、`SkeletonDrawableWrapper.update()` メソッドを呼び、アニメーションを進めるためのデルタ時間（秒単位）を与えます。

`Skeleton` の現在のポーズを `CGImage` としてレンダリングするには、`SkeletonDrawableWrapper/renderToImage(size:backgroundColor:scaleFactor:)` を使います。

`SkeletonDrawable` はネイティブヒープに割り当てられたオブジェクトを保存します。そのため、`SkeletonDrawable` が不要になったら、`SkeletonDrawable.dispose()` を呼び出して、ネイティブオブジェクトを手動で破棄する必要があります。そうしないと、ネイティブのメモリリークになってしまうので注意してください。

> **注意:** `SpineController` は初期化解除時に自動的にこの処理を行います。しかし、`SkeletonDrawableWrapper` を `SpineController` の外部で保持する場合は、上記のようにディスポーズする必要があります。この場合、`SpineController`のコンストラクタのオプションの`disposeDrawableOnDeInit` パラメーターを `false` に設定してください。


## アニメーションの適用
`SpineView` で表示されるスケルトンにアニメーションを適用するには、`SpineController` の コールバックで `AnimationState` を使用します。

> **注意:** アニメーショントラックやアニメーションのキューイングなど、より詳しい情報については、Spineランタイムガイドの[アニメーションの適用](/spine-applying-animations#AnimationState-API)を参照してください。

トラック0に特定のアニメーションを設定するには、 `AnimationState.setAnimationByName()` を呼び出します：

```Swift
@StateObject
var controller = SpineController(
    onInitialized: { controller in
    	  // トラック0にwalkアニメーションをセットし、それをループさせます
        controller.animationState.setAnimationByName(
            trackIndex: 0,
            animationName: "walk",
            loop: true
        )
    }
)
```

最初のパラメーターはトラック、2番目のパラメーターはアニメーションの名前、3番目のパラメーターはアニメーションをループさせるかどうかを指定します。

複数のアニメーションをキューに入れることもできます:

```Swift
controller.animationState.setAnimationByName(trackIndex: 0, animationName: "walk", loop: true)
controller.animationState.addAnimationByName(trackIndex: 0, animationName: "jump", loop: false, delay: 2)
controller.animationState.addAnimationByName(trackIndex: 0, animationName: "run", loop: true, delay: 0)
```

`addAnimationByName()` の最初のパラメーターはトラックです。2番目のパラメーターはアニメーションの名前です。3番目のパラメーターはアニメーションをループさせるかどうかを指定します。最後のパラメーターは、このアニメーションが同じトラック上の前のアニメーションと置き換わるまでの時間(ディレイ)を秒単位で指定します。

上の例では、まず `"walk"` アニメーションが再生されます。その2秒後に `"jump"` アニメーションが一度再生され、続いて `"run"` アニメーションに切り替わり、ループします。

あるアニメーションから別のアニメーションに遷移するとき、`AnimationState` はミックスタイムと呼ばれる特定の時間だけアニメーションをミックスします。これらのミックスタイムは `AnimationStateData` インスタンスで定義され、`AnimationState` はそこからミックスタイムを取得します。

`AnimationStateData` インスタンスはコントローラーを介して利用することもできます。デフォルトのミックスタイムや、特定のアニメーションのペアのミックスタイムを設定することができます:

```Swift
controller.animationStateData.defaultMix = 0.2
controller.animationStateData.setMixByName(fromName: "walk", toName: "jump", duration: 0.1)
```

アニメーションを設定または追加すると、`TrackEntry` オブジェクトが返されます。これを利用してアニメーションの再生をさらに変更できます。例えば、アニメーションを逆再生するようにTrackEntryを設定することができます：

```Swift
var entry = controller.animationState.setAnimationByName(trackIndex: 0, animationName: "walk", loop: true)
entry.reverse = true
```

利用できるオプションについて詳しくは [`TrackEntry` クラスのドキュメント](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated.swift)をご覧ください。

> **注意:** `TrackEntry` インスタンスを使用している関数の外部で保持しないでください。TrackEntryは内部で再利用されるため、それが表すアニメーションが完了すると無効になります。

スケルトンをスムーズにセットアップポーズに戻したい場合は、アニメーショントラックに空のアニメーションをセットまたはキューに追加します:

```Swift
controller.animationState.setEmptyAnimation(trackIndex: 0, mixDuration: 0.5)
controller.animationState.addEmptyAnimation(trackIndex: 0, mixDuration: 0.5, delay: 0.5)
```

`setEmptyAnimation()` の最初のパラメーターはトラックを指定します。2番目のパラメーターは、前のアニメーションをミックスアウトし、"空の"アニメーションをミックスするために使用するミックスタイムを秒単位で指定します。

`addEmptyAnimation()` の最初のパラメーターはトラックを指定します。2番目のパラメーターはミックス時間を指定します。3番目のパラメーターはディレイ(秒単位)で、このディレイの後に空のアニメーションがミキシングされてトラック上の前のアニメーションと置き換わります。

`AnimationState.clearTrack()` を使えばトラック上のすべてのアニメーションを即座にクリアすることができます。すべてのトラックを一度にクリアするには  `AnimationState.clearTracks()` を使います。しかしこれはスケルトンを最後に適用されたポーズのままにする点に注意してください。

スケルトンのポーズをセットアップポーズに戻すには、`Skeleton.setToSetupPose()` を使います:

```Swift
controller.skeleton.setToSetupPose()
```

これはボーンとスロットの両方をセットアップポーズの設定にリセットします。スロットだけをセットアップポーズの設定にリセットしたい場合は `Skeleton.setSlotsToSetupPose()` を使用してください。

## AnimationStateイベント
`AnimationState` は、再生中のアニメーションのライフサイクル中に様々なイベントを発行します。必要に応じてこのイベントをリッスンすることで、それらに反応させることができます。SpineランタイムのAPIでは、以下の[イベントタイプ](/git/spine-runtimes/spine-ios/Sources/Spine/Spine.Generated.swift)を定義しています:

* `SPINE_EVENT_TYPE_START`: アニメーションが開始された時に発されます。
* `SPINE_EVENT_TYPE_INTERRUPT`: アニメーションのトラックがクリアされた、または新しいアニメーションが設定されたなどにより中断された時に発されます。
* `SPINE_EVENT_TYPE_COMPLETE`: アニメーションが1ループを完了するごとに発されます。
* `SPINE_EVENT_TYPE_END`: アニメーションが二度と適用されない時に発されます。
* `SPINE_EVENT_TYPE_DISPOSE`: アニメーションのTrackEntryが破棄された時に発されます。
* `SPINE_EVENT_TYPE_EVENT`: ユーザーが定義した[イベント](/spine-events)が発生した時に発されます。

イベントを受け取るには、 [`AnimationStateListener`](/git/spine-runtimes/spine-ios/Sources/Spine/AnimationStateWrapper.swift) コールバックを `AnimationStateWrapper` に登録してすべてのアニメーションでイベントを受け取るか、または `AnimationStateWrapper.setTrackEntryListener()` で再生キューに入った特定のアニメーションの `TrackEntry` に登録します:

```Swift
var walkEntry = controller.animationState.setAnimationByName(0, "walk", true);
controller.animationStateWrapper.setTrackEntryListener(entry: walkEntry) { type, entry, event in
	if let eventk, type == SPINE_EVENT_TYPE_EVENT {
		print("User defined event: \(event.data.name ?? "--")")
	}
}

controller.animationStateWrapper.setStateListener { type, entry, event in
	print("Animation state event \(type)")
}
```

詳しくは [`AnimationStateEvents.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/AnimationStateEvents.swift) をご覧ください。

## スキン
![/img/spine-runtimes-guide/spine-ios/skins.png](/img/spine-runtimes-guide/spine-ios/skins.png)

多くのアプリケーションやゲームでは、髪や目、ズボン、イヤリングやバッグなどのアクセサリーなど、さまざまなアイテムを組み合わせてカスタムアバターを作ることができます。Spineでは、[複数スキンを組み合わせる](/spine-examples-mix-and-match)ことでこれを実現することができます。

以下のようにして、他のスキンからカスタムスキンを作成することができます：

```Swift
var data = controller.skeletonData
var skeleton = controller.skeleton
var customSkin = Skin.create(name: "custom-skin")
customSkin.addSkin(other: data.findSkin(name: "skin-base")!)
customSkin.addSkin(other: data.findSkin(name: "nose/short")!)
customSkin.addSkin(other: data.findSkin(name: "eyelids/girly")!)
customSkin.addSkin(other: data.findSkin(name: "eyes/violet")!)
customSkin.addSkin(other: data.findSkin(name: "hair/brown")!)
customSkin.addSkin(other: data.findSkin(name: "clothes/hoodie-orange")!)
customSkin.addSkin(other: data.findSkin(name: "legs/pants-jeans")!)
customSkin.addSkin(other: data.findSkin(name: "accessories/bag")!)
customSkin.addSkin(other: data.findSkin(name: "accessories/hat-red-yellow")!)
skeleton.skin = customSkin
skeleton.setToSetupPose()
```

まず、`Skin.create()` static関数でカスタムスキンを作成します。

次に、コントローラーから `SkeletonData` を取得します。`SkeletonData.findSkin()` でスキンの名前を検索します。

`Skin.addSkin()` で、新しいカスタムスキンに組み合わせたいスキンをすべて追加します。

最後に、`Skeleton` に新しいスキンを設定し、`Skeleton.setSlotsToSetupPose()` を呼び出して、以前のスキンやアニメーションのアタッチメントが残らないようにします。

> **注意:** `Skin` はC++オブジェクトをラップします。不要になったら `Skin.dispose()` を呼び出して手動で破棄する必要があります。

詳しくは [`DressUp.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/DressUp.swift) をご覧ください。これは `SkeletonDrawableWrapper` を使用してスキンのサムネイルプレビューをレンダリングする方法も実演しています。

## ボーンのトランスフォームの設定
![/img/spine-runtimes-guide/spine-ios/bone-transform.png](/img/spine-runtimes-guide/spine-ios/bone-transform.png)

Spineエディターでスケルトンを構築する際、スケルトンは「スケルトン座標系」と呼ばれる座標系で定義されます。この座標系は、スケルトンがレンダリングされる `SpineView` の座標系と一致しない場合があります。そのため、ユーザーがタッチ操作でボーンを動かせるようにしたい場合などは、`SpineView` に対するタッチ座標をスケルトン座標系に変換する必要があります。

`SpineController` は、関連付けられた `SpineView` からの相対位置 `CGPoint` を受け取り、スケルトン座標系に変換する `toSkeletonCoordinates()` メソッドを提供します。

詳しくは [`IKFollowing.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/IKFollowing.swift) の例を参照してください。

また、`fromSkeletonCoordinates()` を使用して、別の方向に座標を変換することもできます。詳しくは [`DebugRendering.swift`](/git/spine-runtimes/spine-ios/Example/Spine%20iOS%20Example/DebugRendering.swift) の例を参照してください。

# SpineランタイムのAPI呼び出し
Spine iOSは、SpineランタイムAPIのほとんどすべてをSwiftにマッピングしています。例えば `Skeleton` や `AnimationState` のように、`SpineController` や `SkeletonDrawableWrapper/SkeletonDrawable` が返すオブジェクトはspine-cppのAPIをSwiftに1:1変換したものです。そのため、一般的な[Spineランタイムガイド](/spine-runtimes-guide)にある資料のほとんどすべてをSwiftコードに適用できます。

しかしながら、spine-cppブリッジの性質上、以下のような制限があります：

* 返される配列やマップはすべて内部配列のコピーです。それらを変更しても影響はありません。
* ボーンやスロット、その他のSpineオブジェクトを直接、作成、追加、削除することはできません。
* タイムラインのC++クラス階層はSwiftでは公開されていません。