作り途中のアプリのスクショです。まだ全然ちゃっちいです(ちゃっちさがちっとも緩和されない…)。
今デバッグ用に円を表示させてるんですが、要はこの円と中にスプライトが入ってるかを判定したくなって、色々調べました。
何か他のもっと簡単なやり方はありそうな気がするし、というより実装されてそうな気もするんだけど(見つけられなかった)、ただ結構簡単に自作できたんで、忘れないうちにまとめておきます(需要はないような気もするけど…)。
やり方
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;
だけで判定できますね(´・ω・`)