• cocos2dx 2.2.6 + box2d 成就600行代码的 完整桌球游戏


    cocos2dx 的强大,本博主不需要多表明,直接上代码,但是本人保证 绝对运行不了因为不会共享资源。

    头文件

    #include "Box2D/Box2D.h"
    
    #include "GLES-Render.h"
    
    #define PTM_RATIO 32.0f
    
    #include <deque>
    
    typedef deque<b2Body*> deleteBodyDeque;
    
    #define Baiqiu_Tag 100
    #define Hit_qiu_max 6
    
    //碰撞检测器
    class MyContactListener : public b2ContactListener
    {
        
    public:
        
        MyContactListener():_shengyuqiu(Hit_qiu_max){_BodyDeque.clear();};
        
        ~MyContactListener(){};
        
        //碰撞开始
        void BeginContact(b2Contact*contact)
        { // handle begin event
            
            if( contact->GetFixtureA()->GetBody()->GetUserData() == nullptr )
            {
                b2Body* CurBody = contact->GetFixtureB()->GetBody();
                
                auto phy = static_cast<CCPhysicsSprite*>(CurBody->GetUserData() );
                phy->getParent()->setVisible(false);
                _BodyDeque.push_back(CurBody);
            }
            else if( contact->GetFixtureB()->GetBody()->GetUserData() == nullptr )
            {
                b2Body* CurBody = contact->GetFixtureA()->GetBody();
                
                auto phy = static_cast<CCPhysicsSprite*>(CurBody->GetUserData() );
                phy->getParent()->setVisible(false);
                _BodyDeque.push_back(CurBody);
            }
        }
        
        //碰撞结束
        void EndContact(b2Contact* contact)
        { // handle end event
        }
        
        
        
        void PreSolve(b2Contact* contact,const b2Manifold* oldManifold)
        { // handle pre-solve event
        }
        
        
        
        void PostSolve(b2Contact* contact,const b2ContactImpulse* impulse)
        
        { // handle post-solve event
        }
        
        //碰撞检测后,在 box2d step()后执行删除body
        void   deleteBody()
        {
            for( auto Cur:_BodyDeque )
            {
                b2World* Wold = Cur->GetWorld();
                
                auto phy = static_cast<CCPhysicsSprite*>(Cur->GetUserData());
                
                if( phy->getTag() == 100 )
                {
                    CCMessageBox("白球进入,Game Over!", "游戏结束");
                }
                else
                {
                    _shengyuqiu --;
                    
                    if(_shengyuqiu<=0)
                    {
                         CCMessageBox("完成所有目标,Good!", "游戏完成");
                    }
                }
                
                Wold->DestroyBody(Cur);
            }
            
            _BodyDeque.clear();
        }
    private:
        
        deleteBodyDeque     _BodyDeque;
        int                 _shengyuqiu;
    };
    
    class CTableTennis: public CCLayer
    {
        
    public:
        
        CTableTennis():_CurWorld(nullptr),_CurAngle(0.0f),_IsMiaozhun(false){}
        
        ~CTableTennis(){ delete _CurWorld; delete _Gles; delete _ContactListener; }
        
        CREATE_FUNC(CTableTennis);
        
        bool init();
        
        void update( float fdt );
        
        void draw();
        
        virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
        virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
        virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
        
        void registerWithTouchDispatcher(void);
        
        //创建颜色球
        void    createSEqiu( int Max );
        
        //切换坐标系
        b2Vec2 changePos( CCPoint pos )
        {
            return b2Vec2(pos.x/PTM_RATIO, pos.y/PTM_RATIO);
        }
        
        //切换坐标系
        CCPoint changePos( b2Vec2 pos )
        {
            return ccp(pos.x*PTM_RATIO, pos.y*PTM_RATIO);
        }
        
        //根据box2d Body创建台球精灵
        bool    createTaiqiu( const char* SpriteName,b2Body* body_,int Tag = 0 );
        
        //创建球洞的刚体,用于检测进洞
        void    createCheckeD();
        
        //画瞄准虚线
        void    drawDottedLine( CCPoint startPoint, CCPoint endPoint );
        
        //更新瞄准虚线
        void    updateDottedLine( CCPoint startPoint, CCPoint endPoint, CCDrawNode* CurNode = nullptr );
        
        //计算虚线的位置以及角度
        CCPoint    mathDottedLineEnd( float step, float angle );
        
    private:
        
        b2World*         _CurWorld;
        GLESDebugDraw*   _Gles;
        b2Body*          _CurBaiqiu;
        MyContactListener* _ContactListener;
        float              _CurAngle;
        
        CCRect          _miaozhunRect;
        CCRect          _yongliRect;
        
        CCRect          _preYongLi;
        CCRect          _preYongLi2;
        bool            _IsMiaozhun;
    };
    

     cpp

    #include "TableTennis.h"
    
    bool CTableTennis::init()
    {
        auto winSize = CCDirector::sharedDirector()->getWinSize();
        
        if (!CCLayer::init())
        {
            return false;
        }
        
        _ContactListener = new MyContactListener;
        
        _CurWorld = new b2World(b2Vec2(0,0));
        _CurWorld->SetAllowSleeping(true);
        _CurWorld->SetContinuousPhysics(true);
        
        _CurWorld->SetContactListener(_ContactListener);
        
        GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("NewActivity/qiutai_box2d.plist");
        CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("NewActivity/billiards.plist");
        
        b2BodyDef _bodydef;
        _bodydef.position.Set((winSize.width*0.5f- 480.0f)/PTM_RATIO, 0);
        b2Body* taiqiu = _CurWorld->CreateBody(&_bodydef);
        GB2ShapeCache::sharedGB2ShapeCache()->addFixturesToBody(taiqiu, "qiutai");
        
        _bodydef.type = b2_dynamicBody;
        _bodydef.linearDamping = 0.8f;
        //_bodydef.angularDamping = 0.1f;
        b2CircleShape cs;
        cs.m_radius = 0.48f;
        _bodydef.position.Set((winSize.width* 0.5f - 213.0f)/PTM_RATIO, 265.0f/PTM_RATIO);
        _bodydef.bullet = true;
        auto zuoqiu = _CurWorld->CreateBody(&_bodydef);
        
        b2FixtureDef zuoqiufde;
        zuoqiufde.shape =&cs;
        zuoqiufde.friction = 0.0f;
        zuoqiufde.density = 10.0f;
        zuoqiufde.restitution = 0.98f;
        zuoqiu->CreateFixture(&zuoqiufde);
    
        _CurBaiqiu = zuoqiu;
    
        scheduleUpdate();
        
        setTouchEnabled(true);
        
        auto taiqiuzhuo = CCPhysicsSprite::createWithSpriteFrameName("qiutai.png");
        taiqiuzhuo->setAnchorPoint(ccp(0,0));
        taiqiuzhuo->setB2Body(taiqiu);
        taiqiuzhuo->setPTMRatio(PTM_RATIO);
        taiqiu->SetUserData(taiqiuzhuo);
        addChild(taiqiuzhuo);
        
        createTaiqiu( "baiqiu.png", _CurBaiqiu, Baiqiu_Tag );
        
        createSEqiu(Hit_qiu_max);
        
        createCheckeD();
        
        drawDottedLine( changePos(_CurBaiqiu->GetPosition()), mathDottedLineEnd( 430.0f, _CurAngle ) );
        
        _miaozhunRect = CCRect(0,0, winSize.width, winSize.height );
        _yongliRect = CCRect(taiqiuzhuo->getPositionX(), taiqiuzhuo->getPositionY()+52.0f, 120.0f, 400.0f );
        
        auto liliangkuangdise = CCSprite::createWithSpriteFrameName("liliangkuangdise.png");
        liliangkuangdise->setPosition(ccp( taiqiuzhuo->getPositionX()+20.0f, taiqiuzhuo->getPositionY()+taiqiuzhuo->getContentSize().height*0.5f ));
        addChild(liliangkuangdise,100);
        
        auto liliangtiao = CCSprite::createWithSpriteFrameName("liliangtiao1.png");
        liliangtiao->setAnchorPoint(ccp(0.5f,0.0f));
        liliangtiao->setPosition(ccp(liliangkuangdise->getPositionX(), liliangkuangdise->getPositionY() + liliangtiao->getContentSize().height * 0.5f-2) );
        liliangtiao->setRotation(180.0f);
        _preYongLi = liliangtiao->getTextureRect();
        liliangtiao->setTextureRect( CCRectMake(_preYongLi.origin.x, _preYongLi.origin.y, _preYongLi.size.width, _preYongLi.size.height*0.0f) );
        addChild(liliangtiao,100,111 );
        
        auto liliangkuang = CCSprite::createWithSpriteFrameName("liliangkuang1.png");
        liliangkuang->setPosition(liliangkuangdise->getPosition());
        addChild(liliangkuang,101);
        
        auto liliangkuang2dise = CCSprite::createWithSpriteFrameName("liliangkuang2dise.png");
        liliangkuang2dise->setPosition(ccp( winSize.width * 0.5f, 530.0f ));
        addChild(liliangkuang2dise,100,201);
        
        auto liliangtiao2 = CCSprite::createWithSpriteFrameName("liliangtiao2.png");
        liliangtiao2->setAnchorPoint(ccp(0,0.5f));
        liliangtiao2->setPosition(ccp( winSize.width * 0.5f-liliangtiao2->getContentSize().width*0.5f, 530.0f ));
        _preYongLi2 = liliangtiao2->getTextureRect();
        liliangtiao2->setTextureRect( CCRectMake(_preYongLi2.origin.x, _preYongLi2.origin.y, 0, _preYongLi2.size.height));
        addChild(liliangtiao2,100,202);
        
        auto liliangkuang2 = CCSprite::createWithSpriteFrameName("liliangkuang2.png");
        liliangkuang2->setPosition(ccp( winSize.width * 0.5f, 530.0f ));
        addChild(liliangkuang2,100,203);
        
        for (int i = 0; i<3; ++i)
        {
            getChildByTag(i+201)->setVisible(false);
        }
        return true;
    }
    
    void CTableTennis::update( float fdt )
    {
        _CurWorld->Step( fdt, 8, 1 );
        
        _ContactListener->deleteBody();
        
        for (b2Body* Cur = _CurWorld->GetBodyList(); Cur; Cur = Cur->GetNext() )
        {
            if ( Cur->GetType() == b2_dynamicBody && Cur->IsAwake() == true )
            {
                if( abs(Cur->GetLinearVelocity().x) < 0.2f && abs(Cur->GetLinearVelocity().y) < 0.2f )
                {
                    Cur->SetAwake(false);
                }
            }
        }
    
        if(_IsMiaozhun)
        {
            for (b2Body* Cur = _CurWorld->GetBodyList(); Cur; Cur = Cur->GetNext() )
            {
                if ( Cur->GetType() == b2_dynamicBody && Cur->IsAwake() == true )
                {
                    return;
                }
            }
            
            _IsMiaozhun = false;
        }
    }
    
    void CTableTennis::draw()
    {
        CCLayer::draw();
    }
    
    bool CTableTennis::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
    {
        if (_IsMiaozhun)
        {
            return false;
        }
        
        return true;
    }
    
    void CTableTennis::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
    {
        if (_yongliRect.containsPoint(pTouch->getStartLocation()))
        {
            auto juli = pTouch->getStartLocation().y - pTouch->getLocation().y;
            
            if (juli<0) {
                juli = 0;
            }
            else if( juli > _preYongLi.size.height )
            {
                juli = _preYongLi.size.height;
            }
            
            auto liliangtiao = static_cast<CCSprite*>(getChildByTag(111));
            liliangtiao->setTextureRect( CCRectMake(_preYongLi.origin.x, _preYongLi.origin.y, _preYongLi.size.width, juli) );
            
            for (int i = 0; i<3; ++i)
            {
                getChildByTag(i+201)->setVisible(true);
            }
            
            float prelidu = juli/_preYongLi.size.height;
            
            liliangtiao = static_cast<CCSprite*>(getChildByTag(202));
            liliangtiao->setTextureRect( CCRectMake(_preYongLi2.origin.x, _preYongLi2.origin.y, _preYongLi2.size.width*prelidu, _preYongLi2.size.height) );
        }
        else if (_miaozhunRect.containsPoint(pTouch->getStartLocation()))
        {
            if (_miaozhunRect.containsPoint(pTouch->getLocation()))
            {
                auto startPos = changePos(_CurBaiqiu->GetPosition());
                updateDottedLine( startPos, pTouch->getLocation() );
            }
            
        }
    
    }
    
    void CTableTennis::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
    {
        if (_yongliRect.containsPoint(pTouch->getStartLocation()))
        {
            auto liliangtiao = static_cast<CCSprite*>(getChildByTag(111));
            
            auto CurSize = liliangtiao->getTextureRect().size.height;
            
            float prelidu = CurSize/_preYongLi.size.height;
            
            _CurBaiqiu->SetLinearVelocity( changePos( ccpMult( ccpForAngle(_CurAngle) , 1500.0f*prelidu)) );
            
            liliangtiao->setTextureRect( CCRectMake(_preYongLi.origin.x, _preYongLi.origin.y, _preYongLi.size.width, 0) );
            
            if (prelidu != 0.0f )
            {
                _IsMiaozhun = true;
                getChildByTag( 88 )->setVisible(false);
                getChildByTag( 99 )->setVisible(false);
                getChildByTag( 10 )->setVisible(false);
            }
            
            for (int i = 0; i<3; ++i)
            {
                getChildByTag(i+201)->setVisible(false);
            }
        }
    }
    
    void CTableTennis::registerWithTouchDispatcher(void)
    {
        CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();
        pDispatcher->addTargetedDelegate(this, -128, true);
        CCLayer::registerWithTouchDispatcher();
    }
    
    void    CTableTennis::createSEqiu( int Max )
    {
        b2BodyDef _bodydef;
        _bodydef.type = b2_dynamicBody;
        _bodydef.linearDamping = 0.8f;
        _bodydef.bullet = true;
        b2CircleShape cs;
        b2FixtureDef zuoqiufde;
        cs.m_radius = 0.48f;
        zuoqiufde.shape = &cs;
        zuoqiufde.friction = 0.0f;
        zuoqiufde.density = 10.0f;
        zuoqiufde.restitution = 0.98f;
        auto winSize = CCDirector::sharedDirector()->getWinSize();
        
        CCPoint array[6] = { ccp(0.0f,0.0f), ccp( 30.0f, 15.0f ), ccp(30.0f,-15.0f),
                             ccp(60.0f,30.0f), ccp(60.0f,0.0f), ccp(60.0f,-30.0f) };
        
        std::string spriteName[6] = { "huangqiu.png", "lanqiu.png", "lvqiu.png",
                                         "hongqiu.png", "heiqiu.png", "ziqiu.png" };
        
        for (int i = 0 ; i<Max; ++i)
        {
            b2Vec2 CurPos = changePos(ccp(winSize.width*0.5f + 213.0f + array[i].x, 265.0f+array[i].y));
            _bodydef.position.Set(CurPos.x,CurPos.y);
            auto zuoqiu = _CurWorld->CreateBody(&_bodydef);
            zuoqiu->CreateFixture(&zuoqiufde);
            
            createTaiqiu( spriteName[i].c_str(), zuoqiu );
        }
    }
    
    bool    CTableTennis::createTaiqiu( const char* SpriteName,b2Body* body_,int Tag )
    {
        b2Body* TempBody = body_;
        
        if (!TempBody)
        {
            return false;
        }
        
        auto Node = CCNode::create();
        addChild(Node);
        
        auto baiqiu = CCPhysicsSprite::createWithSpriteFrameName(SpriteName);
        
        if (!baiqiu)
        {
            return false;
        }
        
        auto shadow = CCPhysicsSprite::createWithSpriteFrameName("qiuying.png");
        
        if (!shadow)
        {
            return false;
        }
        //taiqiuzhuo->setAnchorPoint(ccp(0,0));
        baiqiu->setB2Body(body_);
        shadow->setB2Body(body_);
        body_->SetUserData(baiqiu);
        baiqiu->setPTMRatio(PTM_RATIO);
        shadow->setPTMRatio(PTM_RATIO);
        Node->addChild(shadow,0,Tag);
        Node->addChild(baiqiu,0,Tag);
        
        return true;
    }
    
    void    CTableTennis::createCheckeD()
    {
        
        b2BodyDef _bodydef;
        _bodydef.position.Set(0, 0);
        b2CircleShape cs;
        cs.m_radius = 0.1f;
        
        b2FixtureDef def;
        def.shape = &cs;
        def.density = 0.0f;
        
        CCPoint array[6] = { ccp(-430.0f,220.0f), ccp( -430.0f,-220.0f ), ccp(0.0f,-230.0f),
            ccp(430.0f,-220.0f), ccp(430.0f,220.0f), ccp(0.0f,230.0f) };
        
        auto winSize = CCDirector::sharedDirector()->getWinSize();
        
        for (int i = 0 ; i<6; ++i)
        {
            b2Vec2 CurPos = changePos(ccp(winSize.width*0.5f + array[i].x, 266.0f +array[i].y));
            _bodydef.position.Set(CurPos.x,CurPos.y);
            auto zuoqiu = _CurWorld->CreateBody(&_bodydef);
            zuoqiu->CreateFixture(&def);
        }
    }
    
    void    CTableTennis::drawDottedLine( CCPoint startPoint, CCPoint endPoint )
    {
        auto drawNode = CCDrawNode::create();
    
        updateDottedLine(startPoint,endPoint,drawNode );
        
        drawNode->setZOrder(30);
        drawNode->setTag(10);
        this->addChild(drawNode);
    }
    
    void    CTableTennis::updateDottedLine( CCPoint startPoint, CCPoint endPoint, CCDrawNode* CurNode )
    {
        CCDrawNode* drawNode = CurNode;
        
        if (!CurNode)
        {
            drawNode = static_cast<CCDrawNode*>(getChildByTag(10));
        }
        
        drawNode->setVisible(true);
        drawNode->clear();
        
        float stepLength = 6.0f;
        float spaceLength = 15;
        
        auto CurVector = ccpNormalize( ccpSub(endPoint,  startPoint) );
        
        CCPoint nextPoint = startPoint;
        CCPoint dictPoint;
        
        while (true)
        {
            float endpos =ccpLength(ccpSub(endPoint, nextPoint));
            
            if ( endpos <= spaceLength )
            {
                break;
            }
            
            endpos =ccpLength(ccpSub(endPoint, dictPoint));
            
            if ( endpos <= stepLength )
            {
                break;
            }
            
            dictPoint = ccpAdd(nextPoint, ccpMult(CurVector, stepLength));
            
            drawNode->drawSegment(nextPoint, dictPoint, 1, ccc4f(1.0f, 1.0f, 1.0f, 0.3f));
            
            nextPoint = ccpAdd(dictPoint, ccpMult(CurVector, spaceLength));
            
        }
        
        auto zhunxing = getChildByTag( 88 );
        if (!zhunxing)
        {
            zhunxing = CCSprite::createWithSpriteFrameName( "zhunxing.png" );
            addChild(zhunxing, 20, 88 );
        }
        zhunxing->setVisible(true);
        zhunxing->setPosition(endPoint);
        
        auto qGan = getChildByTag( 99 );
        if (!qGan)
        {
            qGan = CCSprite::createWithSpriteFrameName( "qiugan.png" );
            qGan->setAnchorPoint( ccp(1.05f,0.5f) );
            addChild(qGan, 20, 99 );
        }
        qGan->setVisible(true);
        qGan->setPosition(startPoint);
        
        _CurAngle = ccpToAngle(CurVector);
        
        qGan->setRotation( CC_RADIANS_TO_DEGREES( -_CurAngle ) );
        
    }
    
    CCPoint    CTableTennis::mathDottedLineEnd( float step, float angle )
    {
        auto StartPos_ = changePos(_CurBaiqiu->GetPosition());
        
        CCPoint endPos_;
        
        endPos_.x = step * cosf( angle ) + StartPos_.x;
        endPos_.y = step * sinf(angle) + StartPos_.y;
        
        return endPos_;
    }
    

     少量注释,看不懂那就没办法,没那个时间写!

    运行gif

  • 相关阅读:
    Activity 横竖屏生命周期
    gradle wrapper, gradle ,gradle plugin 之间的关系
    《构建之法》第八、九章学习总结
    《构建之法》第六、七章学习总结
    《构建之法》第三、四、五章学习总结
    《构建之法》第一、二章学习总结
    SQL练习50题(基于MySQL)后25题
    SQL练习50题(基于MySQL)前25题
    轮播2-css
    轮播1-animate-匀速
  • 原文地址:https://www.cnblogs.com/VindyLeong/p/4234048.html
Copyright © 2020-2023  润新知