読者です 読者をやめる 読者になる 読者になる

夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【TravelShooting JP】cocos2dでデバッグ用コリジョン円を表示

TravelShooting JP cocos2d

現在開発中のスペハリ風シューティングゲームTravelShooting JPでは単純な円を使った当り判定を採用しています。2つのノード間の距離とそれぞれのノードが持つコリジョン円の半径を足した値を比較するだけの非常に単純で高速なコリジョン検出方法です。

簡単なのですが、スプライトに表示されているキャラクターの絵と当り判定の大きさは必ずしも一致していないので「あれ?今当ったの?」という事が良くあります。
そのときはコリジョン円の半径を調整したりするのですが、見えない円の大きさを勘で調整するのは無理があります。

そこで、デバッグ用にコリジョン円を見えるようにしてみました。
cocos2dのCCDrawNodeのサブクラスとしてCollisionCircleというクラスを作り、drawDot:メソッドで円を描画します。
Dotと聞くと点しか描けないように思えますが、半径を指定できるので、問題なく円も描けます。
スプライトを表示する様々なクラスからアクセスしたいのでシングルトンとして実装します。

ソースです。

#import "CollisionCircle.h"
#import "Sprite3D.h"


@implementation CollisionCircle {

}

+ (CollisionCircle *)sharedNode
{
    static CollisionCircle* sharedInstance = nil;
    if (!sharedInstance) {
        sharedInstance = [[self alloc] init];
    }
    return sharedInstance;
}

- (id)init
{
    if ((self = [super init])) {
        
        CGSize winSize = [CCDirector sharedDirector].winSize;
        self.position = ccp(winSize.width/2.0, 0.0);
        
        [self scheduleUpdateWithPriority:-10000]; //他のノードのupdateで描画される前にクリア
    }
    return self;
}


- (void)drawRedCircle:(Sprite3D *)node
{
    [self drawCircle:node color:ccc4f(1.0, 0.0, 0.0, 1.0)];
    
}

- (void)drawGreenCircle:(Sprite3D *)node
{
    [self drawCircle:node color:ccc4f(0.0, 1.0, 0.0, 1.0)];
}

- (void)drawBlueCircle:(Sprite3D *)node
{
    [self drawCircle:node color:ccc4f(0.0, 0.0, 1.0, 1.0)];
}

- (void)drawCircle:(Sprite3D *)node color:(ccColor4F)color
{
    CGFloat radius = node.radius * node.scale; 
    [self drawDot:node.position radius:radius color:color];
}

- (void)update:(ccTime)delta
{
    [self clear];
}

@end

前回のポスト、

【cocos2d】scheduleUpdateでプライオリティを指定するのは超重要 - 夏までにiPhone アプリつくってみっか!
で書きましたが、scheduleUpdateのプライオリティ指定は重要です。

あとは、スプライトを表示するノードのupdateメソッドからselfと色を指定してdrawCircle:メソッドを呼ぶだけです。色指定が面倒なので赤、青、緑の円を描くためのメソッドも用意しました。
Sprite3Dというクラスはこのゲーム用にCCSpriteを継承したクラスで、radiusというプロパティにはノードのコリジョン円の半径を入れてあります。

スプライトのクラスからはこのように使います。

- (void)update:(ccTime)delta
{
    [self position3D];
#ifdef COLLISION_CIRCLE
    [[CollisionCircle sharedNode] drawBlueCircle:self];
#endif
}

Common.hには次のような定義を入れて、リリースビルドでは表示されないようにしています。
もちろん、#define COLLISION_CIRCLEの行をコメントアウトすればデバッグビルドでも表示を消す事は可能です。

#ifdef DEBUG
#define COLLISION_CIRCLE
#endif

このCollisionCircleインスタンスはz値を他のノードより高くしてゲーム本体のノードにaddChild
しています。なので、通常のスプライトより必ず手前に表示されます。3D的にはおかしいですが、この方が見やすいと思います。

動画です。

z値を高くしすぎてコリジョン円が画面からはみ出していますが、デバッグ用なのでまあいいでしょう。
ちなみに、CCDrawNodeの処理はかなり軽いようで、コリジョン円の表示によるパフォーマンスへの影響はほとんど感じられませんでした。