SpineをStarling1.7で使う:個別パーツとのあたり判定


前の投稿に書いたように、Spine-StarlingランタイムのSkeletonAnimationに対するタッチ判定は、全体のバウンディングBOXに対して行われます。これは実際にパーツがない部分でもタッチ判定される事がある事を意味します。
個々のパーツ(=スロット=アタッチメント)とのあたり判定の仕組みは公式ランタイムでは用意されていないようです。(海外のフォーラムなどをみても困っている人がいる模様。)探せば誰かが作ったものも見つかるかもしれませんが、各種アタッチメントとの汎用的に使える当たり判定のコードを書いてみたので、紹介しておきます。

動作サンプル


http://harayoki.github.io/qiita_demo/HitTestDemo1/
BODY、両目、両腕、ネクタイ、リボン?それぞれタッチを判別して謎のキャラが動きます。キャラクターの外をタッチするとキャラクターが移動します。回転したり、位置が変わっても正しくパーツ別にタッチ判定できている事が確認できます。

使い方

Staticなメソッドを持つUtilクラスとして作成しました。
SpineHittestUtil.as

sample.as
var isHit:Boolean;

// グローバル座標の場合
var posGrobal:Point = new Point(100, 100);
isHit = SpineHitTestUtil.hitTestWithAttachmentByGlobalPoint(
  skeletonSprite, "slot名", posGrobal);

// ローカル座標の場合
var posSpriteLocal:Point = new Point(10,10);
isHit = SpineHitTestUtil.hitTestWithAttachmentByLocalPoint(
  skeletonSprite, "slot名", posSpriteLocal);

非常に簡単です。SkeletonAnimationの外部で使う事を想定していますが、SkeletonSprite(もしくはSkeletonAnimation)を継承したhitTestクラスで後者を呼び出せば、一部にしかタッチ反応しないSkeletonAnimationも作れるでしょう。

当たり判定をするスロット内のアタッチメントの種類によって挙動が変わります。対応しているアタッチメントは以下です。

  • Region Attachment
    訳すと"領域"ですが、画像パーツの事です。画像の矩形で当たり判定をします。全体の矩形当たり判定と異なり、矩形の回転にも対応しますが、色が透明であるかどうかは判別しません。これが一番お手軽です。

  • BoundingBox Attachment
    訳すと"境界ボックス"で、一般的には全体を覆い囲む矩形を示すのですが、Spineではややこしいことに、自由な多角形領域の事を指します。通常はこれをメインに使う事になると思います。

  • Mesh Attachment
    Spineの売り、Mesh画像との当たり判定です。全てのメッシュと真面目に当たり判定する事も出きそうですが、処理が重くなりそうなので、対象メッシュに対するBoundingBox(一般的な意味)で判定しています。

  • WeightedMeshAttachment Attachment
    追従の重みをつけたMesh Attachmentで、Mesh Attachmentと同様の処理をします。(動作未確認ですが、公式のソースの似たような処理部分を移植したので動くかと。)

くりかえしですが、通常はRegionかBoundingBoxで当たり判定する事を推奨します。

BoundingBox Attachmentについては、公式こちらのページに日本語の解説があります。 http://ja.esotericsoftware.com/spine-bounding-boxes

デモの詳細

右腕、左腕とネクタイがRegion Attachment、両目と体全体がBoundingBox Attachment(下のキャプチャ画像を参照)、リボン部分がMeshです。


目との判定部分


体との判定部分(ラフですが)

デモの主なソースはここにあります。
https://github.com/harayoki/SpineTest1/blob/hittest1/src/demos/HitTestDemo1.as

その他

この原稿を書いている時点でのSpine-Starlingランタイムはデータバージョン3.1.08までをサポートするバージョンです。

RegionとBoundingBoxそれぞれとの当たり判定のアルゴリズムはCrossing Number Algorithmというもので、次のページを参考にしました。
技術者が紹介するテクノロジー 【第2回】点の多角形に対する内外判定

Crossing Number Algorithmは正確な判定ができるものの、そこそこの計算負荷が発生しますので、あるボーンからの距離判定でざっくり代用できるなら、その方が良いですね。

おわりに

自分もこれから、SpineHittestUtilを使って、いろいろ作ってみようと思います。
Meshの正確な当たり判定は、個人的に必要になったら追加で実装する予定です。では。