2014年11月28日

SpriteKitの衝突判定処理でのノードの順序

SpriteKitでは、物理体はcontactTestBitMaskを設定しておけば衝突時に-didBeginContact:が呼ばれる。だが、bodyAとbodyBにはどちらの物理体が設定されているのだろうか?これがわからなければ毎回冗長な判定処理をかかないといけない。


if ( ([nameA isEqualToString:kEnemyName] &&
[nameB isEqualToString:kWeponName]) ||
([nameA isEqualToString:kEnemyName] &&
[nameB isEqualToString:kWeponName]) ) {
}


と思って調べたのだが、少なくともアップルの文書中で見る限り衝突時のA, Bの順序は決まっていないようだ。サンプルコードを見ても何が入るかは任意でありどちらになにが来てもいいように対応すべきという姿勢のようだ。

だが、実装者によってはA,Bの比較は固定であるノードは必ずどちらかにしかこないという前提で書かれたコードを見ることがある。どうも一定の規則に従っているようだ。ブログなどを検索したところ、先に生成されたノードが必ずA、後に生成されたノードがBとなるという記述を見つけた。本当にそうなのだろうか?そうだとしてもAPIリファレンスで明記されないかぎり「現時点での実装ではそうなる」という以上の意味はないだろう。

だが毎回両方の比較をするのは大変。考えられるのは二つ、比較用の関数を用意すること。またはある規則に従って並べ替えること。


static inline BOOL CompareEqual(SKPhysicsContact *contact,
NSString *first,NSString *second)
{
if ([contact.bodyA.node.name isEqualToString:first]) {
if ([contact.bodyB.node.name isEqualToString:second]) {
return YES;
}
} else if ([contact.bodyB.node.name isEqualToString:first]) {
if ([contact.bodyA.node.name isEqualToString:second]) {
return YES;
}
}
return NO;
}


これは前出比較を関数にしただけ。


+ (void)orderdBodies:(SKPhysicsContact *)contact
bodyA:(SKPhysicsBody**)bodyA
bodyB:(SKPhysicsBody**)bodyB
{
if ( !bodyA || !bodyB ) return;
if ( contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask ) {
*bodyA = contact.bodyA;
*bodyB = contact.bodyB;
} else {
*bodyA = contact.bodyB;
*bodyB = contact.bodyA;
}
}


これはカテゴリービットマスクでより上位のビットが1であるほうがA、そうでないほうがBになるようにして返すメソッド。これで比較は決まった順序でできる。
posted by 永遠製作所 at 01:26| 東京 ☀| Comment(0) | TrackBack(0) | iPhone/iPod touch | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック