zoukankan      html  css  js  c++  java
  • [Cocos2d-x For WP8]矩形碰撞检测

        在游戏中我们通常会涉及到两个精灵之间的碰撞的计算,那么在Cocos2d-x里面我们通常会用矩形碰撞检测来计算两个精灵在运动的过程中是否碰撞到了。原理很简单,就是当运动的时候通过精灵的矩形坐标进行遍历来计算精灵之间是否有重合,如果有重合那就证明是碰撞上了。

        下面看一下下面的例子:

    Ball精灵会根据帧速率来进行运动的,下面是Ball精灵的实现代码:

    #ifndef _BALL_H_
    #define _BALL_H_
    
    #include "cocos2d.h"
    /*
    创建一个球的精灵
    */
    class Paddle;
    
    using namespace cocos2d;
    
    class Ball : public CCSprite
    {
        CCPoint m_velocity;
    public:
        Ball(void);
        virtual ~Ball(void);
    
        float radius();
        //BOOL initWithTexture(CCTexture2D* aTexture);
        //virtual void setTexture(CCTexture2D* newTexture);
        void move(ccTime delta);
        void collideWithPaddle(Paddle* paddle);
    
    
    public:
        void setVelocity(CCPoint velocity){m_velocity = velocity;}
        CCPoint getVelocity(){return m_velocity;}
    
    public:
        static Ball* ballWithTexture(CCTexture2D* aTexture);
    };
    
    #endif
    
    
    #include "pch.h"
    #include "Ball.h"
    #include "Paddle.h"
    
    Ball::Ball(void)
    {
    }
    
    Ball::~Ball(void)
    {
    }
    
    float Ball::radius()
    {
        return getTexture()->getContentSize().width / 2;
    }
    //使用CCTexture2D创建ball精灵
    Ball* Ball::ballWithTexture(CCTexture2D* aTexture)
    {
        Ball* pBall = new Ball();
        pBall->initWithTexture(aTexture);
        pBall->autorelease();
    
        return pBall;
    }
    //移动ball精灵
    void Ball::move(ccTime delta)
    {
        //根据m_velocity的数值设置ball精灵的位置
        this->setPosition( ccpAdd(getPosition(), ccpMult(m_velocity, delta)) );
        
        if (getPosition().x > 320 - radius()) 
        {
            setPosition( ccp( 320 - radius(), getPosition().y) );
            m_velocity.x *= -1;
        } 
        else if (getPosition().x < radius()) 
        {
            setPosition( ccp(radius(), getPosition().y) );
            m_velocity.x *= -1;
        }
    }
    //判断是否碰撞到paddle精灵
    void Ball::collideWithPaddle(Paddle* paddle)
    {
        //获取paddle精灵的矩形位置
        CCRect paddleRect = paddle->rect();
        //转化成绝对的位置
        paddleRect.origin.x += paddle->getPosition().x;
        paddleRect.origin.y += paddle->getPosition().y;
        //获取paddle精灵的矩形的相关数值
        float lowY = paddleRect.getMinY();  //CCRect::getMidY(paddleRect);
        float midY = paddleRect.getMidY(); //CCRect::CCRectGetMidY(paddleRect);
        float highY =paddleRect.getMaxY();// CCRect::CCRectGetMaxY(paddleRect);
        
        float leftX = paddleRect.getMinX();//CCRect::CCRectGetMinX(paddleRect);
        float rightX =paddleRect.getMaxX(); //CCRect::CCRectGetMaxX(paddleRect);
        
        if (getPosition().x > leftX && getPosition().x < rightX) {
        
            bool hit = false;
            float angleOffset = 0.0f; 
            //判断是否碰撞到paddle精灵
            if (getPosition().y > midY && getPosition().y <= highY + radius()) 
            {
                setPosition( CCPointMake(getPosition().x, highY + radius()) );
                hit = true;
                angleOffset = (float)M_PI / 2;
            }
            else if (getPosition().y < midY && getPosition().y >= lowY - radius()) 
            {
                setPosition( CCPointMake(getPosition().x, lowY - radius()) );
                hit = true;
                angleOffset = -(float)M_PI / 2;
            }
            
            if (hit) 
            {
                //碰撞到则调整方向
                float hitAngle = ccpToAngle(ccpSub(paddle->getPosition(), getPosition())) + angleOffset;
                
                float scalarVelocity = ccpLength(m_velocity) * 1.05f;
                float velocityAngle = -ccpToAngle(m_velocity) + 0.5f * hitAngle;
                
                m_velocity = ccpMult(ccpForAngle(velocityAngle), scalarVelocity);
            }
        }    
    } 

    Paddle精灵相当于是挡板的意思,Paddle精灵是静止的,当Ball精灵碰撞到Paddle精灵的时候,运动的轨迹就会发生变化。

    Paddle精灵的代码:

    #ifndef _PADDLE_H_
    #define _PADDLE_H_
    
    #include "cocos2d.h"
    
    using namespace cocos2d;
    /*
    创建一个挡板精灵
    */
    typedef enum tagPaddleState 
    {
        kPaddleStateGrabbed,
        kPaddleStateUngrabbed
    } PaddleState; 
    
    class Paddle : public CCSprite, public CCTargetedTouchDelegate
    {
        PaddleState        m_state;
    
    public:
        Paddle(void);
        virtual ~Paddle(void);
    
        CCRect rect();
        bool initWithTexture(CCTexture2D* aTexture);
        virtual void onEnter();
        virtual void onExit();
        bool containsTouchLocation(CCTouch* touch);
        virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
        virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
        virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
    
        virtual void touchDelegateRetain();
        virtual void touchDelegateRelease();
    
        static Paddle* paddleWithTexture(CCTexture2D* aTexture);
    };
    
    #endif
    
    
    #include "pch.h"
    #include "Paddle.h"
    
    Paddle::Paddle(void)
    {
    }
    
    Paddle::~Paddle(void)
    {
    }
    //获取paddle精灵的矩形位置
    CCRect Paddle::rect()
    {
        CCSize s = getTexture()->getContentSize();
        return CCRectMake(-s.width / 2, -s.height / 2, s.width, s.height);
    }
    
    Paddle* Paddle::paddleWithTexture(CCTexture2D* aTexture)
    {
        Paddle* pPaddle = new Paddle();
        pPaddle->initWithTexture( aTexture );
        pPaddle->autorelease();
    
        return pPaddle;
    }
    
    bool Paddle::initWithTexture(CCTexture2D* aTexture)
    {
        if( CCSprite::initWithTexture(aTexture) ) 
        {
            m_state = kPaddleStateUngrabbed;
        }
        
        return true;
    }
    
    void Paddle::onEnter()
    {
        CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();
        pDispatcher->addTargetedDelegate(this, 0, true);
        CCSprite::onEnter();
    }
    
    void Paddle::onExit()
    {
        CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();
        pDispatcher->removeDelegate(this);
        CCSprite::onExit();
    }    
    
    bool Paddle::containsTouchLocation(CCTouch* touch)
    {
        return rect().containsPoint(convertTouchToNodeSpaceAR(touch));;//CCRect::containsPoint(rect(), convertTouchToNodeSpaceAR(touch));
    }
    
    bool Paddle::ccTouchBegan(CCTouch* touch, CCEvent* event)
    {
        if (m_state != kPaddleStateUngrabbed) return false;
        if ( !containsTouchLocation(touch) ) return false;
        
        m_state = kPaddleStateGrabbed;
        return true;
    }
    //移动paddle精灵
    void Paddle::ccTouchMoved(CCTouch* touch, CCEvent* event)
    {
        CCAssert(m_state == kPaddleStateGrabbed, L"Paddle - Unexpected state!");    
        
        CCPoint touchPoint = touch->getLocationInView();
        touchPoint = CCDirector::sharedDirector()->convertToGL( touchPoint );
        
        setPosition( CCPointMake(touchPoint.x, getPosition().y) );
    }
    
    void Paddle::ccTouchEnded(CCTouch* touch, CCEvent* event)
    {
        CCAssert(m_state == kPaddleStateGrabbed, L"Paddle - Unexpected state!");    
        
        m_state = kPaddleStateUngrabbed;
    } 
    
    void Paddle::touchDelegateRetain()
    {
        this->retain();
    }
    
    void Paddle::touchDelegateRelease()
    {
        this->release();
    }

    下面是实现碰撞的Layer:

    //------------------------------------------------------------------
    //
    // 初始化[碰撞的Layer
    //
    //------------------------------------------------------------------
    PongLayer::PongLayer()
    {
        m_ballStartingVelocity = CCPointMake(20.0f, -100.0f);
        //创建ball精灵
        m_ball = Ball::ballWithTexture( CCTextureCache::sharedTextureCache()->addImage("cat.png") );
        m_ball->setPosition( CCPointMake(160.0f, 240.0f) );
        m_ball->setVelocity( m_ballStartingVelocity );
        addChild( m_ball );
        m_ball->retain();
        
        //创建4个Paddle精灵
        CCTexture2D* paddleTexture = CCTextureCache::sharedTextureCache()->addImage("paddle.png");
        m_paddles = new CCArray(4);
        Paddle* paddle = Paddle::paddleWithTexture(paddleTexture);
        paddle->setPosition( CCPointMake(160, 15) );
        m_paddles->addObject( paddle );
        
        paddle = Paddle::paddleWithTexture( paddleTexture );
        paddle->setPosition( CCPointMake(160, 480 - kStatusBarHeight - 15) );
        m_paddles->addObject( paddle );
        
        paddle = Paddle::paddleWithTexture( paddleTexture );
        paddle->setPosition( CCPointMake(160, 100) );
        m_paddles->addObject( paddle );
        
        paddle = Paddle::paddleWithTexture( paddleTexture );
        paddle->setPosition( CCPointMake(160, 480 - kStatusBarHeight - 100) );
        m_paddles->addObject( paddle );
    
        CCObject* arrayItem;
        CCARRAY_FOREACH(m_paddles, arrayItem){
           paddle = (Paddle*)(arrayItem);
           if(!paddle)
                    break;
                addChild(paddle);
        }
        //每一帧刷新ball精灵的运动
        schedule( schedule_selector(PongLayer::doStep) );
    }
    
    PongLayer::~PongLayer()
    {
        m_ball->release();
        m_paddles->release();
    }
    
    void PongLayer::resetAndScoreBallForPlayer(int player)
    {
        m_ballStartingVelocity = ccpMult(m_ballStartingVelocity, -1.1f);
        m_ball->setVelocity( m_ballStartingVelocity );
        m_ball->setPosition( CCPointMake(160.0f, 240.0f) );
    }
    
    void PongLayer::doStep(ccTime delta)
    {
        //移动ball精灵
        m_ball->move(delta);
        Paddle* paddle;
        CCObject* arrayItem;
        CCARRAY_FOREACH(m_paddles, arrayItem){
           paddle = (Paddle*)(arrayItem);
           if(!paddle)
                    break;
                //判断ball精灵是否碰到paddle精灵
                m_ball->collideWithPaddle( paddle );
        }
        //判断是否碰到边界
        if (m_ball->getPosition().y > 480 - kStatusBarHeight + m_ball->radius())
            resetAndScoreBallForPlayer( kLowPlayer );
        else if (m_ball->getPosition().y < -m_ball->radius())
            resetAndScoreBallForPlayer( kHighPlayer );
        m_ball->draw();
    } 

    在helloworld项目中加入该Layer

    CCScene* HelloWorld::scene()
    {
        CCScene * scene = NULL;
        do 
        {   // 'scene'是一个可以自动释放的对象
            scene = CCScene::create();
            //创建失败跳出循环
            CC_BREAK_IF(! scene);
            PongLayer *pongLayer = new PongLayer();
            scene->addChild(pongLayer);
        } while (0);
    
        // 返回scene
        return scene;
    }

    运行的效果:

  • 相关阅读:
    WINCE6.0+S3C6410睡眠和唤醒的实现
    WINCE6.0+S3C6410的触摸屏驱动
    S3C6410的Bootloader的两个阶段BL1和BL2编译相关学习
    amix vim vimrc 3.6 [_vimrc x64 vim (WorkPlace)]配置
    异常的开销
    A C# Reading List by Eric Lippert (ZZ)
    SQL SERVER 2008中定时备份数据库任务的创建与删除
    ASP.NET26个常用性能优化方法
    如何使用四个语句来提高 SQL Server 的伸缩性
    Cookies揭秘 [Asp.Net, Javascript]
  • 原文地址:https://www.cnblogs.com/linzheng/p/3279517.html
Copyright © 2011-2022 走看看