Cocos 2 d-x 2.0ボタン加速処理の詳細分析

15204 ワード


[Cococos 2 d-x関連教程は紅孩児のゲームプログラミングの道CSDNブログアドレスから来ています。http://blog.csdn.net/honghaier
紅孩児Cocos 2 d-X学習園地QQ 2群:44208467
           Cocos 2 d-x 2.0ボタン加速処理の詳細分析
 また、この章で使用されているCococos 2 d-xバージョンは以下の通りです。
Cococos 2 d-hml 5-v 2.1.1
http://cn.cocos2d-x.org/download
      皆さん、こんにちは、私達はよくレースゲームをします。ボタンを押すと、均等速度しか運動できないといらいらします。ゲームの中で加速度を使って、加速度を利用して物体をよりリアルにコントロールするのは不可欠な技能です。今日はCocococos 2 d-xの中でボタンを使って速度の累積を処理します。
 
    WIN 32プログラミングでは、キーを押すと対応するウィンドウがWMuKEYDOWNメッセージを受信することを知っています。押したキーが文字で入力されると、ウィンドウは次にWMUCHARメッセージを受信します。キーを上げると対応するウィンドウがWMuKEYUPメッセージを受信します。ハロルドの分析の中で、CCGLOW類でメッセージ処理ウィンドウの機能があることを知っています。キーの処理を行うには、キーメッセージを受け取る時に該当する関数を呼び出す必要があります。WMuKEYDOWN、WMuCHAR、WMuKEYUPを受けた時に何をしたかを見てみます。
LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	…
case WM_KEYDOWN:
        if (wParam == VK_F1 || wParam == VK_F2)
        {
            CCDirector* pDirector = CCDirector::sharedDirector();
			// SHIFT     ,        F1                     。
            if (GetKeyState(VK_LSHIFT) < 0 ||  GetKeyState(VK_RSHIFT) < 0 || GetKeyState(VK_SHIFT) < 0)
                pDirector->getKeypadDispatcher()->dispatchKeypadMSG(wParam == VK_F1 ? kTypeBackClicked : kTypeMenuClicked);
        }
		//                   m_lpfnAccelerometerKeyHook     。 
        if ( m_lpfnAccelerometerKeyHook!=NULL )
        {
            (*m_lpfnAccelerometerKeyHook)( message,wParam,lParam );
        }
        break;
    case WM_KEYUP:
		//                   m_lpfnAccelerometerKeyHook     。
        if ( m_lpfnAccelerometerKeyHook!=NULL )
        {
            (*m_lpfnAccelerometerKeyHook)( message,wParam,lParam );
        }
        break;
    case WM_CHAR:
        {
			//                  。
            if (wParam < 0x20)
            {
                if (VK_BACK == wParam)
                {
                    CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
                }
                else if (VK_RETURN == wParam)
                {
                    CCIMEDispatcher::sharedDispatcher()->dispatchInsertText("
", 1); } else if (VK_TAB == wParam) { // tab input } else if (VK_ESCAPE == wParam) { // ESC input CCDirector::sharedDirector()->end(); } } else if (wParam < 128) { // ASCII , 。 CCIMEDispatcher::sharedDispatcher()->dispatchInsertText((const char *)&wParam, 1); } else { // 128 , 。 char szUtf8[8] = {0}; int nLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)&wParam, 1, szUtf8, sizeof(szUtf8), NULL, NULL); CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(szUtf8, nLen); } // m_lpfnAccelerometerKeyHook 。 if ( m_lpfnAccelerometerKeyHook!=NULL ) { (*m_lpfnAccelerometerKeyHook)( message,wParam,lParam ); } } break; … }
 
    CCEGLOViewクラスには、具体的な実際のキー処理を外部関数に渡したメンバー関数の指針mulpfnAccellererermeterKeyHookがあります。
 
じゃ、誰ですか?関数の指針の関数はどこに設定しますか?疑問を残して勉強し続けます。
        CCLayer.hを開けます。CCLayerの声明を見てみます。
クラス  CCDLL CCLayer:public CCNode、public CCTouch Delegate、public  CCAccellerermeterDelegate、public CCKeypeadDelegate
         この行では、CCLayerの本質は何かを明確に知ることができます。入力機能を持つノードです。
CCAccellererermeterDelegateは加速キーのメッセージ処理インターフェースの種類で、加速キーの発生速度の情報を受信して処理することができます。ソースを開けます。
CCAccellererermeterDelegate.hを見てみます。
//             X,Y,Z         。
typedef struct 
{
    double x;
    double y;
    double z;
    double timestamp;
} 
CCAcceleration;

// CCAccelerometerDelegate
class CC_DLL CCAccelerometerDelegate
{
public:
	//  CCAcceleration        。
    virtual void didAccelerate(CCAcceleration* pAccelerationValue) {CC_UNUSED_PARAM(pAccelerationValue);}
};
CCLayer.hに戻ります。
class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate
{
	…
	//  CCAccelerometerDelegate     ,        。
	virtual void didAccelerate(CCAcceleration* pAccelerationValue) 
{CC_UNUSED_PARAM(pAccelerationValue);}
	…
	//            。
bool isAccelerometerEnabled();
//            。
void setAccelerometerEnabled(bool value);
…
protected:   
 bool m_bIsAccelerometerEnabled;
 …
}
CPPを開く:
//            。
bool CCLayer::isAccelerometerEnabled()
{
    return m_bIsAccelerometerEnabled;
}
//            。
void CCLayer::setAccelerometerEnabled(bool enabled)
{
    if (enabled != m_bIsAccelerometerEnabled)
    {
        m_bIsAccelerometerEnabled = enabled;
		//       。
        if (m_bIsRunning)
        {
			//      
            CCDirector* pDirector = CCDirector::sharedDirector();
            if (enabled)
            {
				//           ,                          。
                pDirector->getAccelerometer()->setDelegate(this);
            }
            else
            {   //           ,                       。
                pDirector->getAccelerometer()->setDelegate(NULL);
            }
        }
    }
}
    設備も寂しくないですね。中には加速キーマネージャを得るためのgetAccellerermeter関数があります。
CCDirector.hを開く:
 
cccccellerermeter*ccccell ermeter;
 
CCAccell ermeter類の定義は、CCAccellerero.hにあります。
class CC_DLL CCAccelerometer
{
public:
	//     
    CCAccelerometer();
    ~CCAccelerometer();
	//                  。
    void setDelegate(CCAccelerometerDelegate* pDelegate);
	//           。
    void update( double x,double y,double z,double timestamp );
private:
	//         。
    CCAcceleration m_obAccelerationValue;
	//                。
    CCAccelerometerDelegate* m_pAccelDelegate;
};
その対応するCPPは以下の通りである
namespace
{
	//              。
	//X,Y,Z     
    double            g_accelX=0.0;
    double            g_accelY=0.0;
    double            g_accelZ=0.0;
	//X,Y,Z      
    const double    g_accelerationStep=0.2f;
    const double    g_minAcceleration=-1.0f;
    const double    g_maxAcceleration=1.0f;
	//          ,    val    (           )
    template 
    T CLAMP( const T val,const T minVal,const T maxVal )
    {
        CC_ASSERT( minVal<=maxVal );
        T    result=val;
        if ( resultmaxVal )
            result=maxVal;

        CC_ASSERT( minVal<=result && result<=maxVal );
        return result;
    }
	//        ,           。
    bool handleKeyDown( WPARAM wParam )
    {//              。
        bool    sendUpdate=false
		//       X,Y,Z       。
        switch( wParam )
        {
        case VK_LEFT:
            sendUpdate=true;   
//X       g_accelX=CLAMP( g_accelX-g_accelerationStep,g_minAcceleration,g_maxAcceleration );
            break;
        case VK_RIGHT:
            sendUpdate=true;
//X      
g_accelX=CLAMP( g_accelX+g_accelerationStep,g_minAcceleration,g_maxAcceleration );
            break;
        case VK_UP:
            sendUpdate=true;
//Y      
g_accelY=CLAMP( g_accelY+g_accelerationStep,g_minAcceleration,g_maxAcceleration );
            break;
        case VK_DOWN:
            sendUpdate=true;
//Y      
g_accelY=CLAMP( g_accelY-g_accelerationStep,g_minAcceleration,g_maxAcceleration );
            break;
        case VK_OEM_COMMA:
            sendUpdate=true;
//Z      
g_accelZ=CLAMP( g_accelZ+g_accelerationStep,g_minAcceleration,g_maxAcceleration );
            break;
        case VK_OEM_PERIOD:
            sendUpdate=true;
//Z      
g_accelZ=CLAMP( g_accelZ-g_accelerationStep,g_minAcceleration,g_maxAcceleration );
            break;
        }
		//         。
        return sendUpdate;
    }
	//        ,           。
    bool handleKeyUp( WPARAM wParam )
    {//              。
        bool    sendUpdate=false;
        switch( wParam )
        {
        case VK_LEFT:
        case VK_RIGHT:
            sendUpdate=true;
			//       
            g_accelX=0.0;
            break;
        case VK_UP:
        case VK_DOWN:
            sendUpdate=true;
				//       
            g_accelY=0.0;
            break;
        case VK_OEM_COMMA:
        case VK_OEM_PERIOD:
            sendUpdate=true;
				//       
            g_accelZ=0.0;
            break;
        }
		//         。
        return sendUpdate;
    }
	//        ,           。
    void myAccelerometerKeyHook( UINT message,WPARAM wParam,LPARAM lParam )
    {
		//          
        cocos2d::CCAccelerometer    *pAccelerometer = cocos2d::CCDirector::sharedDirector()->getAccelerometer();
        bool                        sendUpdate=false;
        switch( message )
        {
        case WM_KEYDOWN:
			//          。
            sendUpdate=handleKeyDown( wParam );
            break;
        case WM_KEYUP:
			//          。
            sendUpdate=handleKeyUp( wParam );
            break;
        case WM_CHAR:
            break;
        default:
            // Not expected to get here!!
            CC_ASSERT( false );
            break;
        }
		//       。
        if ( sendUpdate )
        {
			//      。
            const time_t    theTime=time(NULL);
            const double    timestamp=(double)theTime / 100.0;
//                            pAccelerometer->update( g_accelX,g_accelY,g_accelZ,timestamp );
        }
    }
	//    
    void resetAccelerometer()
    {
        g_accelX=0.0;
        g_accelY=0.0;
        g_accelZ=0.0;
    }

}

NS_CC_BEGIN
//    。
CCAccelerometer::CCAccelerometer() : 
    m_pAccelDelegate(NULL)
{
    memset(&m_obAccelerationValue, 0, sizeof(m_obAccelerationValue));
}

//  
CCAccelerometer::~CCAccelerometer() 
{

}
//                    。
void CCAccelerometer::setDelegate(CCAccelerometerDelegate* pDelegate) 
{
	//              
    m_pAccelDelegate = pDelegate;
    if (pDelegate)
    {
        //           ,    ,    CCLayer          ,    CCEGLView                         myAccelerometerKeyHook。
CCEGLView::sharedOpenGLView()->setAccelerometerKeyHook( &myAccelerometerKeyHook );
    }
    else
    {
        //      ,       CCEGLView                。       。
CCEGLView::sharedOpenGLView()->setAccelerometerKeyHook( NULL );
        resetAccelerometer();
    }
}
//        ,        
void CCAccelerometer::update( double x,double y,double z,double timestamp ) 
{
	//            。
    if (m_pAccelDelegate)
    {
        m_obAccelerationValue.x            = x;
        m_obAccelerationValue.y            = y;
        m_obAccelerationValue.z            = z;
        m_obAccelerationValue.timestamp = timestamp;

        //         ,        m_pAccelDelegate      ( CCLayer       )      。
        m_pAccelDelegate->didAccelerate(&m_obAccelerationValue);
    }    
}
ちょっと迷っています。このサークルはどういうことですか?
図を参照:
原理説明:
      現在のデバイスの加速キーマネージャのインスタンスオブジェクトを取得し、受信したキーメッセージをパラメータとしてudate関数を呼び出します。そのudate関数は、キーメッセージ生成の速度情報構造を対応する速度情報処理インターフェース類に転送します。例示的なポインタは、次に、ポインタが指す例示的なオブジェクトから、虚関数didAccellerateを呼び出して、対応する加速効果を達成する。
      速度情報処理インターフェース類(CCAccellerermeterDelegate)の派生クラス、例えばCCLayerとその派生クラスの設定に応答した加速キーメッセージ処理を開始すると、システムは、デバイスの加速キーマネージャ(CCAccellermeter)のインスタンスオブジェクトの速度情報処理インターフェース類(CCAccellermeterDelegate)に設定します。実例的なポインタは、関数myAccellerermeterKeyHookをCCEGLNewクラスのインスタンスで使用されるキーメッセージ処理のコールバック関数として設定します。
    原理説明が分かりました。今はTestCppのAcceelermeterTestを見にきます。
ヘッダファイルを開く:
//   AccelerometerTest。
class AccelerometerTest: public CCLayer
{
protected:
	//           。
CCSprite* m_pBall;
//      。
    double    m_fLastTime;

public:
	//     
    AccelerometerTest(void);
    ~AccelerometerTest(void);
	//     ,            。             。
    virtual void didAccelerate(CCAcceleration* pAccelerationValue);
	//    。
virtual std::string title();
//         。
    virtual void onEnter();
};

//       。
class AccelerometerTestScene : public TestScene
{
public:
	//        。
    virtual void runThisTest();
};
CPPを開く:
//   ,  _pos      。
#define FIX_POS(_pos, _min, _max) \
    if (_pos < _min)        \
    _pos = _min;        \
else if (_pos > _max)   \
    _pos = _max;        \

//  
AccelerometerTest::AccelerometerTest(void)
: m_fLastTime(0.0)
{
}
//  
AccelerometerTest::~AccelerometerTest(void)
{
	//            。   onEnter        。
    m_pBall->release();
}
//    。
std::string AccelerometerTest::title()
{
    return "AccelerometerTest";
}
//         。
void AccelerometerTest::onEnter()
{
	//         。
    CCLayer::onEnter();
	//         
    setAccelerometerEnabled(true);
	//       
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//        。
CCLabelTTF* label = CCLabelTTF::create(title().c_str(), "Arial", 32);
//            。
    addChild(label, 1);
	//         。
    label->setPosition( CCPointMake(s.width/2, s.height-50) );
	//              。
    m_pBall = CCSprite::create("Images/ball.png");
	//             。
    m_pBall->setPosition(ccp(s.width / 2, s.height / 2));
	//         。
    addChild(m_pBall);
	//    ,           。    ,                     。                   。  addChild                  ,     ,       。
    m_pBall->retain();
}
//            。             。
void AccelerometerTest::didAccelerate(CCAcceleration* pAccelerationValue)
{
	//         。
    CCDirector* pDir = CCDirector::sharedDirector();
    CCSize winSize   = pDir->getWinSize();

    //          。
    if ( m_pBall == NULL ) {
        return;
    }
	//           。
    CCSize ballSize  = m_pBall->getContentSize();
	//         。
    CCPoint ptNow  = m_pBall->getPosition();
	//                。
    CCPoint ptTemp = pDir->convertToUI(ptNow);
	//                  。
    ptTemp.x += pAccelerationValue->x * 9.81f;
    ptTemp.y -= pAccelerationValue->y * 9.81f;
	//    OPENGL      。      ,       X,Y             。
    CCPoint ptNext = pDir->convertToGL(ptTemp);
	//     X,Y     ,            。
    FIX_POS(ptNext.x, (ballSize.width / 2.0), (winSize.width - ballSize.width / 2.0));
    FIX_POS(ptNext.y, (ballSize.height / 2.0), (winSize.height - ballSize.height / 2.0));
	//       。
    m_pBall->setPosition(ptNext);
}

//    
void AccelerometerTestScene::runThisTest()
{
	//      AccelerometerTest            。
    CCLayer* pLayer = new AccelerometerTest();
addChild(pLayer);
//new          ,    release   1    。   :addChild(pLayer)                。
    pLayer->release();
	//      。
    CCDirector::sharedDirector()->replaceScene(this);
}
    運転結果は図の通りです。
    キーを押した時:上、下、右、左、小球はそれぞれX、Y、Zの正と負の方向の加速度を発生します。WINDOWSはWMUKEYDOWNメッセージで即時にキー応答を処理した時に遅延間隔があります。ボタンの応答がスムーズではなく、GetKeyStateに変更したらスムーズになります。例えば、CCEGLOWのswapBufferに対応するキーを追加します。判断する
void CCEGLView::swapBuffers()
{
    if (m_hDC != NULL)
    {
        ::SwapBuffers(m_hDC);
    }	
	//      
	if(GetKeyState(VK_LEFT) < 0)
	{
           if ( m_lpfnAccelerometerKeyHook!=NULL )
            {
                (*m_lpfnAccelerometerKeyHook)( WM_KEYDOWN,VK_LEFT,0 );
            }
	}
	….           。
}
      本節はこれで終わります。講義します。