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 );
}
}
…. 。
}
本節はこれで終わります。講義します。