Spine iOSランタイム ドキュメント
ライセンスについて
Spineランタイムをアプリケーションに組み込む前に、必ずSpine Runtimes Licenseを確認してください。
はじめに
Spine iOSランタイムはspine-cppの薄いラッパーを使って実装されています。UIKit
と SwiftUI
の両方を使って実行できます。Swift
と Objective-C
の両方がサポートされています。
レンダリングにはMetalを使用しており、ティントブラックを除くすべてのSpine機能をサポートしています。
インストール方法
Spine iOS は iOS 13 以降でサポートされています。プロジェクトでSpine iOSを使用するには、Swift Package ManagerまたはCocoaPodsを使用してインストールすることができます。
spine-runtimesリポジトリのブランチの major.minor
バージョンが、エクスポートする Spineエディターの major.minor
バージョンと一致していることを確認してください。詳しくは「バージョンの同期」を参照してください。
Swift Package Manager
プロジェクトにSpine iOS SPMパッケージを追加するには:
- Xcodeでご自身のプロジェクトを開いてください。
- Project Settingsに移動します: Project Navigatorでプロジェクトをクリックし、ターゲットの右上にあるプロジェクトを選択します。
- Swift Packagesパッケージを選択します:
Package Dependencies
タブをクリックします。 - パッケージを追加:
+
をクリックして検索欄にgit@github.com:EsotericSoftware/spine-runtimes.git
を入力します。 - 依存関係のルール:
Commit
を選択し、サポートしたいmajor.minor
ブランチの最新の完全なコミットハッシュを入力します。 - 終了: Next をクリックし、Xcodeがパッケージを解決した後、Finish をクリックします。
また、C++サポートを有効にする必要があります:
- Project Settingsに移動します: アプリのメインターゲットをクリックします。
Built Settings
タブを開きます:C++ and Objective-C Interoperability
を探します。C++ / Objective-C++
を選択します。
CocoaPods
バージョン管理方法の性質上、Spine iOSは公開されているCocoaPodsインデックスには含まれていません。ご自身のPodfile
に追加するには、以下のように .podspec
ファイルへリンクさせる必要があります。その際、正しいmajor.minor
を使用してください。
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
をインポートすることができます:
サンプル
Spine iOSランタイムには、利用できる機能セットを実演しているサンプルがいくつか含まれています。
サンプルプロジェクトを実行するには:
- お使いのMacにXcodeをインストールします
- spine-runtimesリポジトリをクローンします:
git clone https://github.com/esotericsoftware/spine-runtimes
- 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
: エクスポートしたSpineスケルトンを読み込み、ビューに表示し、特定のアニメーションを再生するSpineView
とSpineController
の基本的な使い方を実演しています。PlayPauseAnimation.swift
: アニメーションを一時停止して再開する方法を実演しています。AnimationStateEvents.swift
: スロットの色を設定する方法、複数のアニメーションをキューに入れる方法、AnimationStateイベントをリッスンする方法を実演しています。DebugRendering.swift
:SpineController
のonAfterPaint
コールバックを介して、レンダリングされたスケルトンの上にカスタム描画を実行する方法を実演しています。DressUp.swift
: Spineのスキン機能と、キャラクター作成UIで使用するためにスケルトンをサムネイルにレンダリングする方法を実演しています。IKFollowing.swift
: スケルトンのボーンをタッチ入力でドラッグする方法を実演しています。DisableRendering.swift
:SpineView
が画面外に移動したときにレンダリングを無効にする方法を実演しています。これはCPU/GPUリソースを維持する必要がある場合に重要です。SimpleAnimationViewController.m
:UIKit
とObjective-C
でSpine iOS
を使用する方法を示します。
Spine iOSランタイムのアップデート
プロジェクトのSine iOSランタイムをアップデートする前に、Spineエディターとランタイムのバージョン管理に関するガイドを参照してください。
CocoaPodsについては、正しい major.minor
ブランチにリンクしてください。
SPM
の場合は、正しい major.minor
ブランチから正しいコミットハッシュを選択してください。
注意:
Spine iOS
パッケージのmajor.minor
バージョンを変更した場合、使用しているSpineスケルトンを同じmajor.minor
バージョンのSpineエディターを使って再エクスポートする必要があることに注意してください!
Spine iOSを使用する
Spine iOS ランタイムは、Spineで作成されたアニメーションのロード、再生、操作をサポートする汎用spine-cppの慣用的なラッパーです。Spine iOSランタイムは、spine-cpp API のほとんどすべてを慣用的なSwiftとして公開し、Spineスケルトンを簡単に表示、操作するためのSwiftUIとUIKit固有のクラスを提供します。
Spine iOSランタイムは、ティントブラックを除くすべてのSpineの機能をサポートしています。
アセットのマネージメント
Spine iOS用にエクスポートする
以下の実行方法については、Spineユーザーガイド内で紹介されています :
スケルトンのデータとテクスチャアトラスをエクスポートすると、以下のファイルが得られます:
skeleton-name.json
またはskeleton-name.skel
: これはスケルトンとアニメーションのデータを含んでいます。skeleton-name.atlas
: これはテクスチャアトラスの情報を含んでいます。- 1つまたは複数の
.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 iOSのAPIは汎用spine-cppランタイムの上に構築されており、プラットフォームに依存しないコアクラスとSpineスケルトンのロード、クエリ、変更、アニメーションを行うアルゴリズムを提供します。コアクラスは、Swiftのイディオムクラスとして公開されます。
ここではSpine iOSを使用する際によく見ることになる最も重要なコアクラスについてのみ簡単に説明しています。Spineランタイムのアーキテクチャ、コアクラス、APIの使用法の詳細については、Spineランタイムガイドを参照してください。
Atlas
クラスは、.atlas
ファイルとそれに対応する .png
画像ファイルからロードしたデータを保管します。
SkeletonData
クラスは、.json
または .skel
ファイルからロードされたデータを保管します。このスケルトンデータには、ボーン階層、スロット、アタッチメント、コンストレイント、スキン、アニメーションに関する情報が含まれます。SkeletonData
インスタンスは、通常、それが表すスケルトンで使用されるイメージをソースとする Atlas
(アトラス) も一緒に提供することによってロードされます。これは、Skeleton
インスタンスを作成するための設計図として機能します。複数のスケルトンを同じアトラスとスケルトンデータからインスタンス化し、ロードされたデータを共有することで、ロード時間と実行時のメモリ消費を最小限に抑えることができます。
Skeleton
クラスは、SkeletonData
インスタンスから作成されたスケルトンのインスタンスを格納します。スケルトンは現在のポーズを保管します。つまり、ボーンの位置、スロット、アタッチメント、アクティブなスキンの現在の構成を保管します。現在のポーズは、手動でボーンのトランスフォームを変更するか、より一般的には、AnimationState
を介してアニメーションを適用することで計算されます。
AnimationState
クラスは、 スケルトンに適用する(単数または複数の)アニメーションを追跡し、最後のレンダリングフレームと現在のレンダリングフレームの間の経過時間に基づいてそれらのアニメーションを進め、ミックスを行い、スケルトンインスタンスにアニメーションを適用して現在のポーズを設定します。AnimationState
は AnimationStateData
インスタンスに問い合わせ(処理要求)をして、アニメーション間のミキシング時間を取得します。特定のアニメーション間に使用するミキシング時間が無ければデフォルトミックスタイムを取得します。
Spine iOSランタイムはこれらのコアクラスの上に構築されています。
SpineView / SpineUIView
SpineView
struct は SpineUIView
の周りの UIViewRepresentable
なので、後者はSwiftUI
プロジェクトで使用できます。SpineUIView
はMTKViewのサブクラスです。
以降、どちらかを参照するときは SpineView
を使用します。
SpineView
は Spineのスケルトンをロードして表示する役割を果たします。最低限、ビューはスケルトンとアトラスファイルをどこからロードするかを知る必要があり、アニメーションの設定やスケルトンのスキンの変更など、ウィジェットの状態を変更する役割を持つ SpineController
インスタンスを受け取ることができます。
SpineController
は ObservableObject
で、@State
変数内に保持されます。最も単純なケースでは、SpineView
は以下のように他のビュー body
の中でインスタンス化できます:
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
、RawBounds
、SkinAndAnimationBounds
のクラスドキュメントを参照してください。backgroundColor
: ビューの背景色。デフォルトではUIColor.clear
が使用されます。
SpineView
には、レンダリングを無効にするオプションのバインディングパラメータisRendering
があります。詳細については、DisableRendering.swift
の例を参照してください。
SpineController
SpineController
は、SpineView
のスケルトンのアニメーションを制御します。コントローラーは、コンストラクタの引数としてオプションのコールバックセットを提供します。これは SpineView
のライフタイム中に特定のタイミングで呼び出されます。
コントローラは、Atlas
、SkeletonData
、Skeleton
、AnimationState
などの Spineランタイム API オブジェクトを返すゲッターを通して、スケルトンの状態を公開します。詳細については、Spineランタイムガイドおよびクラスのドキュメントを参照してください。
SpineView
を初期化すると、コントローラーの onInitialized()
コールバックメソッドが呼び出されます。このメソッドを使用して、再生するアニメーションを設定したり、スケルトンのスキンを設定したりすることができます。
初期化が完了すると、SpineView
は画面のリフレッシュレートで連続的にレンダリングされます。各フレームで AnimationState
が現在キューに入っているアニメーションに基づいて更新され、Skeleton
に適用されます。
次に、オプションの onBeforeUpdateWorldTransforms()
コールバックが呼び出され、Skeleton.updateWorldTransform()
を使って現在のポーズが計算される前にスケルトンを変更することができます。
現在のポーズが計算された後、オプションの onAfterUpdateWorldTransforms()
コールバックが呼び出され、スケルトンがレンダリングされる前に現在のポーズをさらに修正することができます。手動でボーンの位置を変更したいならばここが適切です。
SpineView
によってスケルトンがレンダリングされる前に、オプションの onBeforePaint()
コールバックが呼び出されます。これにより、ビュー階層でスケルトンの後ろにあるべき背景やその他のオブジェクトをレンダリングすることができます。
SpineWidget
が現在のスケルトンのポーズをレンダリングした後、オプションの onAfterPaint()
コールバックが呼び出されます。
デフォルトでは、ビューはスケルトンを毎フレーム更新してレンダリングします。SpineController.pause()
メソッドを使用すると、スケルトンの更新とレンダリングを一時停止できます。SpineController.resume()
メソッドで、スケルトンの更新とレンダリングを再開できます。SpineController.isPlaying
プロパティは、現在の再生状態を報告します。詳しくはサンプル 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ランタイムガイドのアニメーションの適用を参照してください。
トラック0に特定のアニメーションを設定するには、 AnimationState.setAnimationByName()
を呼び出します:
var controller = SpineController(
onInitialized: { controller in
// トラック0にwalkアニメーションをセットし、それをループさせます
controller.animationState.setAnimationByName(
trackIndex: 0,
animationName: "walk",
loop: true
)
}
)
最初のパラメーターはトラック、2番目のパラメーターはアニメーションの名前、3番目のパラメーターはアニメーションをループさせるかどうかを指定します。
複数のアニメーションをキューに入れることもできます:
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
インスタンスはコントローラーを介して利用することもできます。デフォルトのミックスタイムや、特定のアニメーションのペアのミックスタイムを設定することができます:
controller.animationStateData.setMixByName(fromName: "walk", toName: "jump", duration: 0.1)
アニメーションを設定または追加すると、TrackEntry
オブジェクトが返されます。これを利用してアニメーションの再生をさらに変更できます。例えば、アニメーションを逆再生するようにTrackEntryを設定することができます:
entry.reverse = true
利用できるオプションについて詳しくは TrackEntry
クラスのドキュメントをご覧ください。
注意:
TrackEntry
インスタンスを使用している関数の外部で保持しないでください。TrackEntryは内部で再利用されるため、それが表すアニメーションが完了すると無効になります。
スケルトンをスムーズにセットアップポーズに戻したい場合は、アニメーショントラックに空のアニメーションをセットまたはキューに追加します:
controller.animationState.addEmptyAnimation(trackIndex: 0, mixDuration: 0.5, delay: 0.5)
setEmptyAnimation()
の最初のパラメーターはトラックを指定します。2番目のパラメーターは、前のアニメーションをミックスアウトし、"空の"アニメーションをミックスするために使用するミックスタイムを秒単位で指定します。
addEmptyAnimation()
の最初のパラメーターはトラックを指定します。2番目のパラメーターはミックス時間を指定します。3番目のパラメーターはディレイ(秒単位)で、このディレイの後に空のアニメーションがミキシングされてトラック上の前のアニメーションと置き換わります。
AnimationState.clearTrack()
を使えばトラック上のすべてのアニメーションを即座にクリアすることができます。すべてのトラックを一度にクリアするには AnimationState.clearTracks()
を使います。しかしこれはスケルトンを最後に適用されたポーズのままにする点に注意してください。
スケルトンのポーズをセットアップポーズに戻すには、Skeleton.setToSetupPose()
を使います:
これはボーンとスロットの両方をセットアップポーズの設定にリセットします。スロットだけをセットアップポーズの設定にリセットしたい場合は Skeleton.setSlotsToSetupPose()
を使用してください。
AnimationStateイベント
AnimationState
は、再生中のアニメーションのライフサイクル中に様々なイベントを発行します。必要に応じてこのイベントをリッスンすることで、それらに反応させることができます。SpineランタイムのAPIでは、以下のイベントタイプを定義しています:
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
: ユーザーが定義したイベントが発生した時に発されます。
イベントを受け取るには、 AnimationStateListener
コールバックを AnimationStateWrapper
に登録してすべてのアニメーションでイベントを受け取るか、または AnimationStateWrapper.setTrackEntryListener()
で再生キューに入った特定のアニメーションの TrackEntry
に登録します:
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
をご覧ください。
スキン
多くのアプリケーションやゲームでは、髪や目、ズボン、イヤリングやバッグなどのアクセサリーなど、さまざまなアイテムを組み合わせてカスタムアバターを作ることができます。Spineでは、複数スキンを組み合わせることでこれを実現することができます。
以下のようにして、他のスキンからカスタムスキンを作成することができます:
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
をご覧ください。これは SkeletonDrawableWrapper
を使用してスキンのサムネイルプレビューをレンダリングする方法も実演しています。
ボーンのトランスフォームの設定
Spineエディターでスケルトンを構築する際、スケルトンは「スケルトン座標系」と呼ばれる座標系で定義されます。この座標系は、スケルトンがレンダリングされる SpineView
の座標系と一致しない場合があります。そのため、ユーザーがタッチ操作でボーンを動かせるようにしたい場合などは、SpineView
に対するタッチ座標をスケルトン座標系に変換する必要があります。
SpineController
は、関連付けられた SpineView
からの相対位置 CGPoint
を受け取り、スケルトン座標系に変換する toSkeletonCoordinates()
メソッドを提供します。
詳しくは IKFollowing.swift
の例を参照してください。
また、fromSkeletonCoordinates()
を使用して、別の方向に座標を変換することもできます。詳しくは DebugRendering.swift
の例を参照してください。
SpineランタイムのAPI呼び出し
Spine iOSは、SpineランタイムAPIのほとんどすべてをSwiftにマッピングしています。例えば Skeleton
や AnimationState
のように、SpineController
や SkeletonDrawableWrapper/SkeletonDrawable
が返すオブジェクトはspine-cppのAPIをSwiftに1:1変換したものです。そのため、一般的なSpineランタイムガイドにある資料のほとんどすべてをSwiftコードに適用できます。
しかしながら、spine-cppブリッジの性質上、以下のような制限があります:
- 返される配列やマップはすべて内部配列のコピーです。それらを変更しても影響はありません。
- ボーンやスロット、その他のSpineオブジェクトを直接、作成、追加、削除することはできません。
- タイムラインのC++クラス階層はSwiftでは公開されていません。