作り途中のアプリのスクショです。まだ全然ちゃっちいです(ちゃっちさがちっとも緩和されない…)。
今デバッグ用に円を表示させてるんですが、要はこの円と中にスプライトが入ってるかを判定したくなって、色々調べました。
何か他のもっと簡単なやり方はありそうな気がするし、というより実装されてそうな気もするんだけど(見つけられなかった)、ただ結構簡単に自作できたんで、忘れないうちにまとめておきます(需要はないような気もするけど…)。
やり方
cocos2d-xにはポイント同士の距離を求めるccpDistance()と2つの点から一番近い位置を求めるclampfとかccpClampといった便利な関数があるんで、それを使います。
参考にしたページのとやり方はまんま同じです。
円のクラスを作成する(CCCircle)
cocos2d-xには円を表示するようなのがなかったから、それだけ自作します。
どうせならaddChildできた方がなにかと便利だから、CCNodeを実装させます。
//CCCircle.h
class CCCircle : public CCNode{
CC_SYNTHESIZE(float , radius , Radius);
public:
CCCircle(const CCPoint $point , float $radius):radius($radius){
this->setPosition($point);
};
static CCCircle* create(CCPoint $point , float $radius);
virtual bool init();
//円と四角形の衝突判定
bool intersectRect(const CCRect &$rect);
//円同士の衝突判定
bool intersectCircle(CCCircle* $circle);
//ついで
CCDrawNode* getDrawNode(ccColor4F $f);
};
//CCCircle.cpp
#include "CCCircle.h"
using namespace cocos2d;
CCCircle* CCCircle::create(CCPoint $point , float $radius){
CCCircle* pret = new CCCircle($point , $radius);
if(pret && pret->init()){
pret->autorelease();
return pret;
}
CC_SAFE_DELETE(pret);
pret = NULL;
return NULL;
}
bool CCCircle::init(){
if(!CCNode::init()) return false;
return true;
}
bool CCCircle::intersectRect(const CCRect &$rect){
CCPoint pos = ccp(clampf(m_obPosition.x , $rect.origin.x , $rect.origin.x + $rect.size.width),
clampf(m_obPosition.y , $rect.origin.y , $rect.origin.y + $rect.size.height));
return ccpDistance(m_obPosition , pos) < radius;
}
bool CCCircle::intersectCircle(CCCircle* $circle){
return ccpDistance(m_obPosition , $circle->getPosition()) < (radius + $circle->getRadius());
}
CCDrawNode* CCCircle::getDrawNode(ccColor4F $f){
CCDrawNode* draw = CCDrawNode::create();
draw->drawDot(ccp(0,0) , radius , $f);
return draw;
}
m_obPositionはCCNodeのメンバ変数です。setPositionのですね。
intersectRectで当たり判定をしてます。clampfで最短距離の位置を求め、円の中心からの距離を求めて、それが円の半径より短ければ衝突してるという感じです。
使ってみる
実際に使ってみます。
CCSize winSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint winPoint = CCDirector::sharedDirector()->getVisibleOrigin();
CCPoint pos = ccp(winPoint.x + winSize.width / 2 , winPoint.y + winSize.height / 2);
//画面の中心に作成する
CCCircle* circle = CCCircle::create(pos , 300.0f);
circle->setTag(1);
this->addChild(circle);
//別のターゲット
CCSprite* pSprite = CCSprite::create("coin.png");
pSprite->setPosition(ccp(winPoint.x + winSize.width / 2 + 100 , winPoint.y + winSize.height / 2 + 100));
pSprite->setTag(2);
this->addChild(pSprite);
//デバッグ用で
CCDrawNode* nodes = circle->getDrawNode(ccc4f(1.0f,1.0f,1.0f,0.8f));
nodes->setPosition(pos);
this->addChild(nodes , 100);
...
//別の場面で取り出して当たり判定してみる
CCCircle* circle = (CCCircle*)this->getChildByTag(1);
CCSprite* sprite = (CCSprite*)this->getChildByTag(2);
if(circle->intersectRect(sprite->boundingBox())){
CCLOG("あたったよ。よかったね。");
}
実行すると、無事「あたったよ。よかったね。」と言ってもらえた\(^o^)/
まとめ
なんというか、ブログを書くたびに色々な意味で恥ずかしくなっちゃうんだけど(自分の初心者っぷりとか…)、とりあえずわざわざクラスなんて作らなくても
CCPoint circlePos = ccp(0,0); CCPoint pos = ccp(clampf(circlePos.x , $rect.origin.x , $rect.origin.x + $rect.size.width), clampf(circlePos.y , $rect.origin.y , $rect.origin.y + $rect.size.height)); float radius = 100.0f; bool hantei = ccpDistance(circlePos , pos) < radius;
だけで判定できますね(´・ω・`)
