作り途中のアプリのスクショです。まだ全然ちゃっちいです(ちゃっちさがちっとも緩和されない…)。
今デバッグ用に円を表示させてるんですが、要はこの円と中にスプライトが入ってるかを判定したくなって、色々調べました。
何か他のもっと簡単なやり方はありそうな気がするし、というより実装されてそうな気もするんだけど(見つけられなかった)、ただ結構簡単に自作できたんで、忘れないうちにまとめておきます(需要はないような気もするけど…)。
やり方
cocos2d-xにはポイント同士の距離を求めるccpDistance()と2つの点から一番近い位置を求めるclampfとかccpClampといった便利な関数があるんで、それを使います。
参考にしたページのとやり方はまんま同じです。
円のクラスを作成する(CCCircle)
cocos2d-xには円を表示するようなのがなかったから、それだけ自作します。
どうせならaddChildできた方がなにかと便利だから、CCNodeを実装させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | //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で最短距離の位置を求め、円の中心からの距離を求めて、それが円の半径より短ければ衝突してるという感じです。
使ってみる
実際に使ってみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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^)/
まとめ
なんというか、ブログを書くたびに色々な意味で恥ずかしくなっちゃうんだけど(自分の初心者っぷりとか…)、とりあえずわざわざクラスなんて作らなくても
1 2 3 4 5 | 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; |
だけで判定できますね(´・ω・`)