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

ライセンスについて

Spineランタイムをアプリケーションに組み込む前に、必ずSpine Runtimes Licenseを確認してください。

はじめに

このページは、当社が提供している公式PixiJSランタイムの統一ページです。公式PixiJSランタイムの一覧と、それぞれの互換バージョンは以下の通りです:

ランタイム PixiJSのバージョン 更新状況
spine-pixi-v8

8 (minimum 8.16)

現在も更新中

spine-pixi-v7

7 (minimum 7.2.0)

現在も更新中

spine-pixi

7 (minimum 7.2.0)

更新終了(spine-pixi-v7へ移行してください)

特に断りのない限り、例やGitHubファイルへのリンクはv8バージョンを参照しています。ただし、パスやリンクから「-v8」を「-v7」に置き換えるだけで、すべてが v7 バージョンに適用されます。

spine-pixiランタイムは、レンダラーに依存しない Spine Runtimes コア API の TypeScript 実装であるspine-ts coreをベースとして実装されています。

spine-pixi-v8WebGLまたはWebGPUの両方を使用してレンダリングできます。spine-pixi-v7 は WebGLを使用してレンダリングされます。(WebGPUサポートは、PixiJS 8で導入されました。)Canvas APIsを使用したレンダリングはサポートされていないので注意してください。

spine-pixiランタイムはすべてのSpineの機能をサポートしています。

インストール方法

PixiプロジェクトでSpine PixiJSを使用するには、まずそのソースをインクルードする必要があります。

バニラJavaScriptの場合

バニラJavaScript(カスタマイズされていないJavaScript)では、scriptタグを使ってunpkgからspine-pixi-v8ランタイムをインクルードできます(または自分でホストします):

<script src="https://unpkg.com/@esotericsoftware/spine-pixi-v8@4.2.*/dist/iife/spine-pixi-v8.js"></script>

注意: spine-pixiの major.minor バージョンがエクスポートを行ったSpineエディターの major.minor と一致していることを確認してください。詳しくは「バージョンの同期」を参照してください。

これでSpineエクステンションが自動的にインストールされ、Pixiプロジェクトで spine-pixi-v8 ランタイムを使用できるようになります。完全な例は index.html をご覧ください。

spine-pixi-v8パッケージは、デバッグ用のソースマップも提供しています。また、spine-pixi-v8のminified版も提供しています。利用するにはunpkgのURLの .js ファイルの末尾を .min.js に置き換えてください。

spine-pixi-v8.js を自分でビルドしたい場合は、 spine-tsのREADME.mdに記載されている指示に従ってください。

NPM または Yarn の場合

依存関係の管理にNPMまたはYarnを使用している場合は、通常の方法でspine-pixi-v8を追加します:

npm install @esotericsoftware/spine-pixi-v8@~4.2.0

注意: spine-phaserの major.minor バージョンがエクスポートを行ったSpineエディターの major.minor と一致していることを確認してください。詳しくは「バージョンの同期」を参照してください。

次に、Spineクラスをインポートします:

import PIXI from "pixi.js"
import { Spine } from '@esotericsoftware/spine-pixi-v8';

これでSpineエクステンションが自動インストールされ、選択したSpine PixiJSランタイムをプロジェクトで使用できるようになります。最小限の例として esbuild/TypeScript project プロジェクトを参照してください。

当社のモジュールパッケージにはデバッグと開発を改善するためにソースマップと d.ts タイピングが含まれています。

サンプル

spine-pixiランタイムには、利用できる機能セットを実演しているサンプルが多数含まれています。

サンプルをローカルで実行するには:

  1. お使いのオペレーティングシステムにGitとNode.jsをインストールします。
  2. spine-runtimesリポジトリをクローンします: git clone https://github.com/esotericsoftware/spine-runtimes
  3. spine-runtimes/spine-ts に移動して npm install & npm run dev を実行します。

これにより、spine-pixi-v8ランタイムをビルドし、ブラウザを開いてspine-tsをベースとしているすべてのランタイムのサンプルの目次を表示することができます。

気になったspine-pixi-v8のサンプルをクリックして、spine-runtimes/spine-ts/spine-pixi-v8/example フォルダ内のコードをチェックしてみてください。

spine-pixi-v8ランタイムのアップデート

プロジェクトのspine-pixi-v8ランタイムをアップデートする前に、Spineエディターとランタイムのバージョン管理に関するガイドをよく確認してください。

バニラJavaScriptでspine-pixi-v8ランタイムをアップデートする場合は、src 属性またはunpkgからspine-pixi-v8を取得する script タグのバージョン文字列を変更してください。

NPM、またはYarnで依存関係を管理している場合にspine-pixi-v8ランタイムをアップデートするには、package.json ファイルのバージョン文字列を変更してください。

注意: spine-pixi-v8パッケージの major.minor バージョンを変更する場合、Spineエディターの major.minor バージョンも変更してSpineスケルトンを再エクスポートする必要があります。詳しくは「バージョンの同期」を参照してください。

spine-pixi-v8を使用する

Spine PixiJSランタイムはすべてのSpineの機能をサポートしています。spine-pixi-v8 は、レンダリングにWebGLまたはWebGPUのどちらでも使用できます。spine-pixi-v7 は、レンダリングにWebGLを使用します(WebGPUサポートは PixiJS 8 で導入されました)。Canvas APIを使用したレンダリングはサポートされていません。

spine-pixi-v8 ではキャンバスレンダリングが利用可能ですが、以下の制限があります。

  • スロットオブジェクト(addSlotObject を通じてスロットにアタッチされた Pixi コンテナ)はレンダリングされません
  • ティントブラック(2色ティント)はサポートされていません
  • ブレンドモードはサポートされていません

アセットのマネージメント

Spine PixiJSランタイム用にエクスポートする

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

  1. スケルトン&アニメーションデータのエクスポート
  2. スケルトンの画像を含むテクスチャアトラスのエクスポート

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

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

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

これらのファイルを提供する際には、サーバーが正しいMIMEタイプを出力するようにしてください:

  • skel ファイルは application/octet-stream
  • json ファイルは application/json
  • atlas ファイルは application/octet-stream
  • png ファイルは image/png

Spineアセットの更新

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

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

コアクラス

Spine PixiJSのAPIは、汎用TypeScript spine-coreランタイムの上に構築されており、プラットフォームに依存しないコアクラスとSpineスケルトンのロード、クエリ、変更、アニメーションを行うアルゴリズムを提供します。

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

TextureAtlas クラスは、.atlas ファイルとそれに対応する .png 画像ファイルからロードしたデータを保管します。

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

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

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

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

Spine Pixiランタイム

spine-pixi-v8ランタイムは、自動的に2つの Asset タイプの拡張機能、skeletonLoaderatlasLoaderをPixiにインストールします。これらは、エクスポートされた .json.skel、および..atlas ファイルを(事前に)ロードする機能をPIXI.Assetsに追加します。

Spine クラスは、Pixiの ViewContainer クラス (PixiJS 7の Container)を拡張し、ロードしたスケルトンデータとアトラスファイルから Spine コンテナインスタンスを作成するファクトリ関数を提供します。

さらに、PixiJS v8では、WebGPUPipes、WebGLPipes、CanvasPipesを拡張した、 SpinePipeがインストールされます。最終的には、DarkTintBatcher がインストールされます。これは、ティントブラックをサポートするために使用されるバッチャーです。 PixiJS v7では、RendererPlugin タイプの拡張機能をインストールされます。この拡張機能は、少なくとも1つのアタッチメントにティントブラックを使用する Spineコンテナをレンダリングするために使用します。

Spineアセットのロード

.json/.skel ファイルや .atlas ファイルのようなSpineアセットは、Assets.load のような PIXI.Assets クラスのインスタンスで利用可能な通常の関数によってロードされます。

Spine コンテナのインスタンスを作成する前に、それぞれのスケルトンファイルとアトラスファイルをロードする必要があります。これを行うには、Assets.add 関数と Assets.load 関数を使用します。

  • Assets.add({ alias: string, src: string }): URLを使用してアセットのエイリアスを解決する(関連づける)方法を指定できます。この関数は、すべてのスパインアセットファイル(.json、.skel.atlas)に使用できます。
  • Assets.load(string[]):Assets.add で追加したアセットエイリアスをロードします。

例えばスケルトンデータを skeleton.skel というバイナリ形式のスケルトンファイルにエクスポートし、アトラスを skeleton.atlas というファイルに、対応する1つの skeleton.png ファイルと一緒にエクスポートしたと仮定した場合、以下のようにしてアセットをロードすることができます:

PIXI.Assets.add({ alias: "skeleton-data", src: "path/to/skeleton.skel" });
PIXI.Assets.add({ alias: "skeleton-atlas", src: "path/to/skeleton.atlas" });
await PIXI.Assets.load["skeleton-data", "skeleton-atlas"];

Assets.load 関数は、skeleton.skel ファイルからSkeletonDataをロードし、キー skeleton-data の下にキャッシュします。また、skeleton.atlas ファイルから TextureAtlasをロードし、対応する skeleton.png ファイルからテクスチャをロードします。アトラスは、キー skeleton-atlas の下にキャッシュされます。個々のテクスチャアトラスページ画像は明示的にロードする必要はなく、透過的にロードされます。

カスタムアトラスページのテクスチャの指定

デフォルトでは、アトラスローダーは .atlas ファイルで参照されているテクスチャ画像を自動的にロードします。ただし、data.images メタデータオプションを使用することで、独自のテクスチャを指定することも可能です。これは、あらかじめロードされたテクスチャがある場合や、別のソースからのテクスチャを使用したい場合に便利です。

javascript
// アトラスの最初のページ用に単一のテクスチャを指定する
await PIXI.Assets.load({
   src: "path/to/skeleton.atlas",
   data: { images: myTextureSource }
});

// 名前で複数のアトラスページ用のテクスチャを指定する
await PIXI.Assets.load({
   src: "path/to/skeleton.atlas",
   data: {
      images: {
         "skeleton.png": firstPageTextureSource,
         "skeleton2.png": secondPageTextureSource
      }
   }
});

// TextureSourceオブジェクトの代わりにURLを指定することも可能です
await PIXI.Assets.load({
   src: "path/to/skeleton.atlas",
   data: {
      images: {
         "skeleton.png": "path/to/custom-texture.png"
      }
   }
});

images オプションには、以下の値を指定できます。

  • TextureSource または string (URL):最初のアトラスページに使用されます
  • { [キー: string]: TextureSource | string }:アトラスページ名をテクスチャまたはURLにマッピングします

また、imageMetadata オプションを使用して、テクスチャローダーに追加のメタデータを渡すこともできます:

javascript
await PIXI.Assets.load({
   src: "path/to/skeleton.atlas",
   data: {
      imageMetadata: { /* テクスチャローダーに渡されるオプション */ }
   }
});

事前ロードが完了したら、Asset.get(atlasKey) を介して TextureAtlas にアクセスできます。同様に、Asset.get(skeletonKey) で、生(raw) .skel ファイルにアクセスできます。この段階では、SkeletonData インスタンスはまだ利用できないことに注意してください。

生のスケルトン データとアトラス単体では、アニメーションやレンダリングはできません。代わりに、それらから Spineコンテナが構築されます。同じアセットキーでインスタンス化された Spine コンテナは、同じスケルトンデータとアトラスを共有します。

Pixi bundlesを使用してアセットをロードすることもできます。 Assets.inittexturePreference.formattexturePreference.resolution プロパティを動作させるには、format FILENAME@RESOLUTION.FORMAT.atlas を使用してアトラス名を指定する必要があります。 以下は、バンドルの manifest.json ファイルの例と、優先 formatresolution を指定してロードする方法の例です:

json
{
   "bundles": [
      {
         "name": "spineboy",
         "assets": [
            {
               "alias": ["spineboyAtlas"],
               "src": [
                  "spineboy.png.atlas",
                  "spineboy@2x.png.atlas",
                  "spineboy@3x.png.atlas",
                  "spineboy.webp.atlas",
                  "spineboy@2x.webp.atlas",
                  "spineboy@3x.webp.atlas"
               ]
            },
            { "alias": ["spineboyData"], "src": ["spineboy-pro.json"] }
         ]
      }
   ]
}
javascript
// 指定されたマニフェストとプリファレンスでアセットを初期化
await PIXI.Assets.init({
basePath: './assets/spineboy-bundle',
manifest: './manifest.json',
texturePreference: {
   resolution: Math.min(PIXI.utils.isMobile.any ? window.devicePixelRatio : 3, 3),
   format: ['webp', 'png'],
},
});

// スケルトンデータとアトラスを含むバンドルをロード
await PIXI.Assets.loadBundle("spineboy");

Spineコンテナインスタンスの作成

生のスケルトンデータと対応するアトラスがロードされたら、Spine コンテナを作成できます。

spine-pixi-v8 バージョン 4.2での作成方法

バージョン 4.2 では、静的な from() メソッドを使用して、ロードされたアセットから Spineコンテナを作成します。

javascript
// Pixi appを作成
const app = new PIXI.Application({ ... });
...
// Spine.from() を使用してSpineコンテナを作成
const spineboy = Spine.from({ skeleton: "spineboyData", atlas: "spineboyAtlas", ... });

// Spineコンテナをステージに追加
app.stage.addChild(spineboy);

spine-pixi-v8 バージョン 4.3以降の作成方法

バージョン 4.3以降では、以下のようにSpine のコンストラクタにオプションを直接渡すことができます:

javascript
// Pixi appを作成
const app = new PIXI.Application({ ... });
...
// SpineFromOptionsをコンストラクタに直接渡してSpineコンテナを作成
const spineboy = new Spine({ skeleton: 「spineboyData」, atlas: 「spineboyAtlas」 });
// Spineコンテナをステージに追加
app.stage.addChild(spineboy);

Spine コンストラクタ(4.3 以降で使用)および Spine.from()(4.2で使用)は、SpineFromOptions をパラメーターとして受け付けます。必要な情報は以下の通りです:

  • skeleton: Assetsに事前にロードされたスケルトンファイル(.skel または .json)のアセット名
  • atlas: Assetsに事前にロードされたアトラスファイルのアセット名
  • (オプション) scale: skeleton readerに渡される値。省略された場合は1が渡されます。
  • (オプション) darkTint: true の場合、ティントブラックのレンダラーを使ってスケルトンをレンダリングします。false の場合、デフォルトのpixiレンダラーを使ってスケルトンをレンダリングします。undefined の場合、少なくとも1つのスロットがティントブラックを持っていれば、ティントブラックのレンダラーを使用します。
  • (オプション) autoUpdate: Spineインスタンスの autoUpdate の値を設定します。省略された場合は true に設定され、アニメーションは自動的に再生されます。それ以外の場合は update メソッドを呼び出す必要があります。
  • (オプション) boundsProvider: 使用する境界プロバイダーを定義します。未定義の場合、境界は動的で、要求されたときに現在のフレームに基づいて計算されます。詳しくは境界セクションを参照してください。
  • (オプション) allowMissingRegions: true の場合、スケルトンで参照されている領域がアトラスに存在しない場合でも、アトラスアタッチメントローダーがロードを継続できるようになります。省略された場合は false に設定されます。
  • (オプション) ticker: autoUpdatetrue の際に自動更新に使用するティッカー。省略された場合は Ticker.shared が使用されます。詳しくはカスタムティッカーの使用のセクションを参照してください。

高度なユースケース (4.3以降)

初期化プロセスをより細かく制御するには、静的関数 createOptions() を使用して、コンストラクタに渡す前に初期化設定を別途生成することができます:

javascript
// 初期化オプションを作成
const options = Spine.createOptions({ skeleton: "spineboyData", atlas: "spineboyAtlas" });

// その後、事前に作成したオプションを使用して Spine コンテナを作成
const spineboy = new Spine(options);

// Spine コンテナをステージに追加
app.stage.addChild(spineboy);

createOptions() 関数は、Spine コンストラクタに渡すことができるのと同じ SpineFromOptions パラメーターを受け取り、SpineOptions を返します。これは、設定を事前に準備したい場合や、複数インスタンスで同じ設定を再利用したい場合、または Spine クラスをサブクラス化してカスタム Spineコンテナを作成する場合に便利です。

注: from() 静的メソッドの使用はバージョン 4.3で非推奨となり、バージョン 4.4で削除される予定です。SpineFromOptions を使用してコンストラクタを直接呼び出す方法に移行するか、オプションの作成とインスタンス化を分離する必要がある場合は createOptions() を使用してください。

キャッシュされた SkeletonData のアンロード

同じ skeletonatlas、および scale から作成された Spine コンテナは、キャッシュされた SkeletonData を共有します。Spine キャッシュからこれを削除するには、Spineコンテナを破棄する前に unloadFromCache() を呼び出してください:

javascript
spineboy.unloadFromCache();
spineboy.destroy();
await PIXI.Assets.unloadBundle("spineboy");

該当の SkeletonData を使用している既存のSpine コンテナは引き続き動作します。unloadFromCache() は解析済みの SkeletonData のみを削除します。元のアセットをアンロードするには、PIXI.Assets.unload() または PIXI.Assets.unloadBundle() を使用してください。

Spineコンテナ

Spine コンテナは Pixi ViewContainer (PixiJS 7ではContainer)を拡張したもので、Skeleton とそれに関連する AnimationState の保存、更新、レンダリングを行います。Spineコンテナのインスタンスは、前のセクションで説明したように、スケルトンデータとアトラスから作成されます。SkeletonAnimationState は、それぞれ skeleton フィールドと state フィールドからアクセスできます。

(autoUpdatetrue の場合は)各フレームごとに、Spineコンテナは以下のことを行います:

  • AnimationState を更新
  • AnimationStateSkeleton に適用
  • Skeleton のワールドトランスフォームを更新して、新しいポーズにする
  • Skeleton を現在のポーズで描画

境界

デフォルトでは、Spine コンテナは動的な境界を持っています。getBounds 関数を呼び出すと、現在のフレームに基づいて境界が計算されます。 これは、メッシュハルに基づく正確な相互作用が必要な場合に便利です。 ただし、幅を変更すると現在のフレームに基づいてスケルトンがスケーリングされるため、スケルトンの正確なサイズを設定するには最適ではないかもしれません。 さらに、境界が要求されるたびに境界を再計算することは、パフォーマンスに影響を与える可能性があります。

一度だけ計算される、より一貫性のある境界が必要な場合は、コンストラクタまたは実行時に SpineBoundsProvider を指定します。 境界プロバイダーは、Spineゲームオブジェクトのバウンディングボックスのサイズを決定します。利用可能な SpineBoundsProvider の実装は以下のとおりです:

  • SetupPoseBoundsProvider: スケルトンのセットアップポーズに基づいてバウンディングボックスを計算します。
  • SkinsAndAnimationBoundsProvider: 与えられたスキンとアニメーションの組み合わせにおける最大境界に基づいてバウンディングボックスを計算します。
  • AABBRectangleBoundsProvider: コンストラクタで指定した固定サイズを常に返します。

また、SpineBoundsProvider インターフェイスを実装することで、カスタムの SpineBoundsProvider を作成することもできます。

詳細は、こちらのシグネチャとjsdocを参照してください。

異なる境界プロバイダーとその効果を比較するには、bounds.htmlの例を参照してください。

カスタムティッカーの使用

デフォルトでは、autoUpdatetrue の場合、Spine コンテナは Ticker.shared を使用して、各フレームごとにスケルトンとアニメーションの状態を自動的に更新します。その代わりにカスタムティッカーを指定することも可能です。これは、複数のSpineオブジェクトの再生速度をまとめて制御したい場合や、ティッカーの停止・開始によってアニメーションを一時停止・再開したい場合に便利です。

カスタムティッカーを使用するには、コンストラクタのオプションとして渡します:

javascript
// カスタムティッカーを作成
const myTicker = new PIXI.Ticker();
myTicker.start();

// カスタムティッカーを使用したSpineコンテナを作成
const spineboy = new Spine({
   skeleton: "spineboyData",
   atlas: "spineboyAtlas",
   ticker: myTicker,
});

// ティッカーを使用して、すべてのSpineオブジェクトの再生速度を制御する
myTicker.speed = 0.5; // Half speed

// すべてのアニメーションを一時停止する
myTicker.stop();

// すべてのアニメーションを再開する
myTicker.start();

ティッカーは、ticker プロパティを使用して実行時に変更できます:

javascript
// 別のティッカーに切り替える
spineboy.ticker = anotherTicker;

ティッカーを変更する際に autoUpdatetrue の場合、updateコールバックは古いティッカーから新しいティッカーへ自動的に移行されます。

アニメーションの適用

Spine コンテナによって表示されるスケルトンにアニメーションを適用するには、AnimationState を使用します。

注: アニメーショントラックやアニメーションのキューイングなど、より詳細な情報については、Spineランタイムガイドの アニメーションの適用 を参照してください。

トラック0に特定のアニメーションを設定するには、AnimationState の setAnimation メソッドを呼び出します:

javascript
spineObject.state.setAnimation(0, "walk", true);

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

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

javascript
spineObject.state.setAnimation(0, "walk", true);
spineObject.state.addAnimation(0, "jump", 2, false);
spineObject.state.addAnimation(0, "run", 0, true);

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

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

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

AnimationStateData インスタンスは SpineGameObject からも利用できます。デフォルトのミックスデュレーションや、特定のアニメーションのペアのミックスデュレーションを設定することができます:

javascript
spineObject.state.data.setDefaultMix = 0.2;
spineObject.state.data.setMix("walk", "jump", 0.1);

アニメーションを設定または追加すると、TrackEntry オブジェクトが返されます。例えば、アニメーションを逆再生するようにTrackEntryを設定することができます:

javascript
const entry = spineObject.state.setAnimation(0, "walk", true);
entry.mixDuration = 0.4;
entry.reverse = true;

利用できるオプションについて詳しくはTrackEntryクラスのドキュメントをご覧ください。

注意: TrackEntryインスタンスを使用している関数の外部で保持する場合には注意が必要です。TrackEntryは内部で再利用されるため、TrackEntryのdisposeイベントが発生すると無効になります。

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

javascript
spineObject.state.setEmptyAnimation(0, 0);
spineObject.state.addAnimation(0, "walk", 0).mixDuration = 0.5;
spineObject.state.addEmptyAnimation(0, 0.5, 6);

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

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

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

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

javascript
spineObject.skeleton.setupPose();

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

AnimationStateイベント

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

  • start: アニメーションが開始された時に発されます。
  • interrupt: アニメーションのトラックがクリアされた、または新しいアニメーションが設定されたなどにより中断された時に発されます。
  • end: アニメーションが二度と適用されない時に発されます。
  • dispose: アニメーションのTrackEntryが破棄された時に発されます。
  • complete: アニメーションが1ループを完了するごとに発されます。
  • event: ユーザーが定義したイベントが発生した時に発されます。

イベントを受け取るには、AnimationStateListenerコールバックを、すべてのアニメーションでイベントを受信するAnimationStateか、キューされた特定のアニメーションのTrackEntryに登録します:

javascript
spineObject.state.addListener({
   start: (entry) => log(`Started animation ${entry.animation.name}`),
   interrupt: (entry) => log(`Interrupted animation ${entry.animation.name}`),
   end: (entry) => log(`Ended animation ${entry.animation.name}`),
   dispose: (entry) => log(`Disposed animation ${entry.animation.name}`),
   complete: (entry) => log(`Completed animation ${entry.animation.name}`),
   event: (entry, event) => log(`Custom event for ${entry.animation.name}: ${event.data.name}`)
})

trackEntry.listener = {
   event: (entry, event) => log(`Custom event for ${entry.animation.name}: ${event.data.name}`)
}

詳しくはevents-example.htmlをご覧ください。

スキン

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

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

javascript
const skeletonData = spineObject.skeleton.data;
const skin = new spine.Skin("custom");
skin.addSkin(skeletonData.findSkin("skin-base"));
skin.addSkin(skeletonData.findSkin("nose/short"));
skin.addSkin(skeletonData.findSkin("eyelids/girly"));
skin.addSkin(skeletonData.findSkin("eyes/violet"));
skin.addSkin(skeletonData.findSkin("hair/brown"));
skin.addSkin(skeletonData.findSkin("clothes/hoodie-orange"));
skin.addSkin(skeletonData.findSkin("legs/pants-jeans"));
skin.addSkin(skeletonData.findSkin("accessories/bag"));
skin.addSkin(skeletonData.findSkin("accessories/hat-red-yellow"));
spineObject.skeleton.setSkin(skin);
spineObject.skeleton.setupPoseSlots();

まず、Skin() コンストラクタで新しい空のスキンを作成します。

次に、スケルトンから SkeletonData を取得します。これは SkeletonData.findSkin() でスキンを名前から探すのに使用します。

Skin.addSkin() で新しいスキンにまとめたいスキンをすべて追加します。

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

コード例の全文については mix-and-match-example.html を確認してください。

ボーンのトランスフォームの設定

Spineエディター内でスケルトンを構築する際、スケルトンは、スケルトンのワールド座標系または「スケルトン座標系」と呼ばれるもので定義されます。この座標系は、Pixiの座標系と一致しない場合があります。そのため、例えばユーザーがタッチでボーンを動かせるようにしたい場合などはSpine コンテナに対するマウス座標やタッチ座標は、スケルトン座標系に変換する必要があります。

Spineコンテナには pixiWorldCoordinatesToBone(point: { x: number, y: number}, bone: Bone) というメソッドがあり、Spine コンテナからの相対点を取り、指定したボーンからの相対点をスケルトンの座標系に変換します。

その逆、つまりスケルトン座標系からPixi座標系への変換は、Spine.skeletonToPixiWorldCoordinates(point: { x: number, y: number}) で行えます。

コード例の全文については control-bones-example.html を確認してください。

Pixiオブジェクトをスロットに追加する

Spine クラスには、pixi Container をスロットにアタッチしたり、デタッチしたりするために使える3つの便利なメソッドがあります。

addSlotObject (slotRef: number | string | Slot, pixiObject: Container, options?: { followAttachmentTimeline?: boolean }): void

これは slotRef で参照されているスロットに pixiObject を追加します。これには名前、スロットのインデックス、またはスロットオブジェクト自体を渡すことができます。

Pixiオブジェクトは、1つのスロットに1つだけ割り当てることができます。一度追加されると、Pixiオブジェクトのトランスフォームやマスクなど、特定のプロパティは Spine オブジェクトによって自動的に変更されます。

followAttachmentTimeline オプションは、現在のアタッチメントの表示とスロットの表示を同期させることができます。デフォルトでは false に設定されています。

このような理由から、追加したオブジェクトをより確実にコントロールするために、追加したいオブジェクトをPixi Container にラップすることを強くお勧めします。これにより、Spine による自動修正に制限されることなく、複数のPixiオブジェクトを追加し、位置、角度、スケールなどを調整することができます。

コンテナを削除したい場合は、これに対応したメソッドを呼び出します:

removeSlotObject (slotRef: number | string | Slot, pixiObject?: Container): void

pixiObject はオプションです。渡された場合、Pixiオブジェクトは slotRef で参照されているスロットにあるものと一致する場合のみ削除されます。

Pixiオブジェクトは取り除かれるだけで、破棄されないことに注意してください。また、手動で追加したPixiオブジェクトのライフサイクルに注意してください。

すべてのコンテナを削除したい場合は、代わりに以下を呼び出してください:

removeSlotObjects (): void

スロットにアタッチされたPixiオブジェクトを取得するには、以下のメソッドを使用します:

getSlotObject (slotRef: number | string | Slot): Container | undefined

slotRef で参照されているスロットにアタッチされている Container があれば、それを返します。

完全なサンプルコードは slot-objects.html を参照してください。

メッシュバッチサイズ

v7では Spine オブジェクトはアタッチメントのレンダリングにPixiメッシュを使用します。Pixiのデフォルトでは、頂点数が100を超えるメッシュはバッチ処理不可能とマークされます。その結果、バッチ処理が中断され、ドローコールの回数が増え、パフォーマンスが低下します。この不都合を解消するには、グローバルの PIXI.Mesh.BATCHABLE_SIZE をスケルトンに合った値に設定します。

spine-pixi-v8にはこの制限はありません。

SpineランタイムAPIアクセス

spine-pixi-v8 APIは、spine-tsコアの上に構築されているため、spine-tsが提供するAPIを全て使用できます。詳しくはSpineランタイムガイドを参照してください。