how to use box2d for collision detection in cocos2

2019-09-09 11:00发布

问题:

my two sprites are roll and hero. i want to detect their collision using box2d in cocos2d-x i have got both the sprites moving on the screen (roll automatically, hero manually).

all i want to do is call the function intersection();

when the two sprites collide. (sprites are declared globally in the *.h file)

#include "GameScene.h"
#include "HomeScene.h"
USING_NS_CC;

CCScene* GameScene::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::node();

    // 'layer' is an autorelease object
    GameScene *layer = GameScene::node();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool GameScene::init()
{

    //////////////////////////////
    // 1. super init first
    if ( !CCLayerColor::initWithColor(ccc4(0,0,0,255) ))
    {
        return false;
    }

    //////////////////////////////
    // 2. add your codes below...
    count=0;
    life=3;
    CCSize WinSize= CCDirector::sharedDirector()->getWinSize();
    // background
    CCSprite * bg=CCSprite::spriteWithFile("bg.png");
    bg->setPosition(CCPointZero);
    bg->setAnchorPoint(CCPointZero);
    bg->setScaleX(WinSize.width/460);
    bg->setScaleY(WinSize.height/325);
    this->addChild(bg,0,1);

    //close button
    CCSprite * back=CCSprite::spriteWithFile("close.png");
    CCSprite * back1=CCSprite::spriteWithFile("closeS.png");
    CCMenuItemSprite *home=CCMenuItemSprite::itemFromNormalSprite(back,back1,this,menu_selector(GameScene::callNext));
    CCMenu *MenuClose=CCMenu::menuWithItem(home);
    MenuClose->setPosition(ccp(WinSize.width-20,WinSize.height-20));
    this->addChild(MenuClose,5,1);

    //life icon
    CCSprite * rc=CCSprite::spriteWithFile("rc.png");
    rc->setPosition(ccp(20,WinSize.height-20));
    this->addChild(rc,5,15);

    //score icon
    CCSprite * dp=CCSprite::spriteWithFile("dp.png");
    dp->setPosition(ccp(55,WinSize.height-20));
    this->addChild(dp,5,18);

    //insert roller at a random place
    roll=CCSprite::spriteWithFile("ball.png");
    int minY = (roll->getContentSize().height/2)+(WinSize.height/(4.5));
    int maxY = (WinSize.height)-  (roll->getContentSize().height/2);
    int rangeY = maxY - minY;

    srand ( time(NULL) );

    int actualY = ( rand() % rangeY ) + minY;
    CCLOG("the actualY is oooooooooooooooooooooooooooooooooooooooooooooooooooooooo %d",actualY);
    roll->setPosition(ccp(20,actualY));
    this->addChild(roll,5,8);

    // Determine speed of the roller
    int minDuration = 3;
    int maxDuration = 7;
    int rangeDuration = maxDuration - minDuration;
    int actualDuration = ( rand() % rangeDuration)+ minDuration;

/*  
//creating constraints for the roller
float maxXX = WinSize.width - roll->getContentSize().width/2;
float minXX =roll->getContentSize().width/2;
if (roll->getPosition().x > maxXX)
{
    roll->setPosition( ccp(maxXX, roll->getPosition().y)) ;
}
else if (roll->getPosition().x < minXX)
{
     roll->setPosition (ccp(minXX,roll->getPosition().y));
}


float maxYY = WinSize.height - roll->getContentSize().height/2;
float minYY = roll->getContentSize().height/2;

if (roll->getPosition().y > maxYY)
{
   roll->setPosition ( ccp(roll->getPosition().x, maxYY));
}
else if (getPosition().y < minYY)
{
   roll->setPosition( ccp(roll->getPosition().x, minYY));
}
*/


    // Create the rolling action   
    roll->runAction(CCRepeatForever::actionWithAction((CCSequence*) CCSequence::actions(
                    CCJumpTo::actionWithDuration( actualDuration,ccp(WinSize.width,( rand() % rangeY ) + minY ),( rand() % rangeY ) + minY,4 ),
                    CCHide::action(), 
                    CCMoveTo::actionWithDuration(0,ccp(20,( rand() % rangeY ) + minY)),
                    CCShow::action(), 
                    CCCallFunc::actionWithTarget( this,callfunc_selector(GameScene::scores)),
                    NULL)) );

    //displaying scores
    sprintf(score,"%d",count);  
    scr= CCLabelBMFont::labelWithString(score , "arial16.fnt");
    scr->setPosition(ccp(55,WinSize.height-20));
    scr->setColor(ccc3(0,0,255));
    this->addChild(scr,50);

    //displaying lifes
    sprintf(lifeLabel,"%d",life);   
    lif= CCLabelBMFont::labelWithString(lifeLabel , "arial16.fnt");
    lif->setPosition(ccp(20,WinSize.height-20));
    lif->setColor(ccc3(0,0,255));
    this->addChild(lif,50);

    // insert animated hero
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("boyJog.plist","boyJog.png");

    CCMutableArray<CCSpriteFrame*> *proFrame = new CCMutableArray<CCSpriteFrame *>;
    hero = CCSprite::spriteWithSpriteFrameName("boyJog1.png");
    hero->setPosition(ccp(WinSize.width/2-30,WinSize.height/(4.5)));
    hero->setAnchorPoint(CCPointZero);

    char buff[60];
    for(int i=1;i<=13;i++)
    {
        sprintf(buff,"boyJog%d.png",i);
        proFrame->addObject( (CCSpriteFrameCache::sharedSpriteFrameCache())->spriteFrameByName(buff));
    }

    CCAnimation *progressAnimation=CCAnimation::animationWithFrames(proFrame, 0.05);

    //set animation object here
    CCAnimate *animate=CCAnimate::actionWithAnimation(progressAnimation,false); 
    hero->runAction(CCRepeatForever::actionWithAction(animate));
    hero->setScale(.5);

    this->addChild( hero);




    //left right button
    CCSprite *moveRight= CCSprite::spriteWithFile("arrowRight.png");
    CCSprite *moveLeft= CCSprite::spriteWithFile("arrowLeft.png");
    CCSprite *moveRightS= CCSprite::spriteWithFile("arrowRight.png");
    CCSprite *moveLeftS= CCSprite::spriteWithFile("arrowLeft.png");

    CCMenuItemSprite *right=CCMenuItemSprite::itemFromNormalSprite(moveRight,moveRightS,this,menu_selector(GameScene::heroRight));
    CCMenuItemSprite *left=CCMenuItemSprite::itemFromNormalSprite(moveLeft,moveLeftS,this,menu_selector(GameScene::heroLeft));
    CCMenu *RL =CCMenu::menuWithItems(left,right,NULL);

    RL->alignItemsHorizontallyWithPadding(20);
    RL->setPosition(ccp(WinSize.width-40,20));
    RL->setOpacity(150);
    this->addChild(RL);


    //jump button
    CCSprite *jump= CCSprite::spriteWithFile("arrowUp.png");
    CCSprite *jumpS= CCSprite::spriteWithFile("arrowUp.png");
    CCMenuItemSprite *mmJump=CCMenuItemSprite::itemFromNormalSprite(jump,jumpS,this,menu_selector(GameScene::heroJump));
    CCMenu *menuJump=CCMenu::menuWithItem(mmJump);
    menuJump->setPosition(ccp(20,20));

    menuJump->setOpacity(150);

    this->addChild(menuJump,5,12);




    //////////////////////////////
    return true;
}


void GameScene::callNext(CCObject *sender)
{
    CCLOG("game played");

    CCDirector::sharedDirector()->replaceScene(CCTransitionFade::transitionWithDuration(1,(HomeScene::scene())));
    //exit(1);
}

void GameScene::heroJump(CCObject *sender)
{
    CCLOG(" U");
    CCSize WinSize= CCDirector::sharedDirector()->getWinSize();
    CCPoint Pt=hero->getPosition();
    hero->runAction(CCJumpTo::actionWithDuration(1,ccp(Pt.x,WinSize.height/(4.5)),50,1));
}
void GameScene::heroLeft(CCObject *sender)
{
    CCLOG(" L");
    CCSize WinSize= CCDirector::sharedDirector()->getWinSize();
    CCPoint Pt=hero->getPosition();
    hero->runAction(CCJumpTo::actionWithDuration(1,ccp(Pt.x-30,WinSize.height/(4.5)),0,1));
    hero->setFlipX(1);
    //hero->runAction(CCRepeatForever::actionWithAction(animate));

}
void GameScene::heroRight(CCObject *sender)
{
    CCLOG(" R");
    CCSize WinSize= CCDirector::sharedDirector()->getWinSize();
    CCPoint Pt=hero->getPosition();
    hero->runAction(CCJumpTo::actionWithDuration(1,ccp(Pt.x+30,WinSize.height/(4.5)),0,1));
    hero->setFlipX(0);
    //hero->runAction(CCRepeatForever::actionWithAction(animate));
}

void GameScene::scores()
{

    count+=10;
    CCLOG("count ==========================%d",count);
    sprintf(score,"%d",count);
    scr->setString(score);
}

void GameScene::intersection()
{
    CCLOG("collided..........................................................");
}

回答1:

Sprited are not colliding. You have to create their physical representation using Box2D, sync graphics and physics. Then you have to implement your own contact listener (inherit from b2ContactListener) and use it to be notified when collision happens.



回答2:

You have to create Bodies for every object you want to apply box2D collision on. The bodies must have fixtures, as fixtures are the one that collides, not the bodies.

Please check this tutorial for box2d.

EDIT:

Just to add: Sprites are just images, and they do not know physics. They must be attached to bodies with fixtures. So that they know that there're some other sprite out there and they need to have a reaction on collision like bouncing back or Just destroy the other sprite.



回答3:

In my opinion, this tutorial was more helpful. And if you don't want your characters to bounce on collision but detect the collision anyway, set their fixtures as sensors. And if you don't want them to collide at all, set their fixture groupIndex with the same integer (better negative).

yourFixtureDef.filter.groupIndex = -1; // for example