上図のテストプログラム画面で、「Keyboard」を選ぶと、下図のキーボードテスト画面になる。
キーボードテスト画面では、キーを押下・リリースすると、そのキーコードが下図のように出力ウィンドウにログとして表示される。
class KeyboardTest : public Layer { public: KeyboardTest(); ~KeyboardTest(); void onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event); void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event); private: Label* _label; }; class KeyboardTestScene : public TestScene { public: virtual void runThisTest(); };
"KeyboardTest.h" では、KeyboardTest, KeyboardTestScene の2つのクラスが宣言されている。
KeyboardTest クラスは、Layer の派生クラスで、キーボードテストクラスの本体クラスだ。
キーが押下された時、リリースされた時に呼ばれるハンドラ2つと、メッセージを表示するためのラベルが宣言されている。
KeyboardTestScene クラスは、TestScene の派生クラスで、キーボードテストクラスをセットアップするためのものだ。 メニューで「Keyboard」が選択されると、TestController::menuCallback() から呼び出される runThisTest() 仮想関数を宣言している。
KeyboardTest::KeyboardTest() { auto s = Director::getInstance()->getWinSize(); auto label = Label::createWithTTF("Keyboard Test", "fonts/arial.ttf", 28); addChild(label, 0); label->setPosition( Vec2(s.width/2, s.height-50) ); auto listener = EventListenerKeyboard::create(); listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed, this); listener->onKeyReleased = CC_CALLBACK_2(KeyboardTest::onKeyReleased, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); // create a label to display the tip string _label = Label::createWithTTF("Please press any key and see console log...", "fonts/arial.ttf", 22); _label->setPosition(Vec2(s.width / 2, s.height / 2)); addChild(_label, 0); _label->retain(); }
まずは KeyboardTest クラスのコンストラクタ。
最初に、Director::getInstance()->getWinSize(); をコールし、ウィンドウサイズを取得。あとで、ラベルの位置指定の時に利用する。
ついで、タイトルラベルを Label::createWithTTF() で生成し、addChild() でレイヤーに追加し、setPosition() で位置決めをしている。
後で出てくる _Label の方はメンバ変数だが、タイトルラベルはここでしか参照されないので、メンバ変数ではなくローカル変数にしたのだと推測される。
次に EventListenerKeyboard::create(); でキーボードイベントリスナを生成し、CC_CALLBACK_2() マクロでイベントハンドラを指定し、
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); でイベントディスパッチャに登録している。
この処理の流れは、マウステストの時にも出てきた。
「イベントリスナー生成」→「ハンドラを登録」→「イベントディスパッチャにリスナーを登録」という流れだ。
次に、メッセージ用のラベルを生成し、位置決め、レイヤーに追加を行い、retain() で参照カウントを+1している。
このテストでは押されたキーのコードをログに出力するので _label をメンバ変数にする必要は無く、タイトルラベル同様にローカル変数にしてもよいのだが、
何故かメンバ変数になっている。
当初は、押下・リリースされたキーのコードをログに出すのではなく、ラベルに表示する予定だったのかもしれない。
ちなみに、タイトルラベルの方は、コンストラクタを抜けると、Label::~Label() がコールされ、表示は残るが、オブジェクト自体破棄されてしまうようだ。
Obj-C がらみで cocos2d からのものかもしれないが、ちょっと微妙な仕様である。
KeyboardTest::~KeyboardTest() { _label->release(); }
上記は KeyboardTest デストラクタの実装。
メッセージラベルをリリースし、参照カウントをデクリメントすることで、オブジェクトを破棄している。
void KeyboardTest::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event) { log("Key with keycode %d pressed", keyCode); } void KeyboardTest::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event) { log("Key with keycode %d released", keyCode); }
上記は、キー押下・リリースイベントハンドラの実装。
両方共、キーコードをメッセージ付きでログ出力しているだけだ。
void KeyboardTestScene::runThisTest() { auto layer = new KeyboardTest(); addChild(layer); Director::getInstance()->replaceScene(this); layer->release(); }
最後に、キーテスト本体クラスを生成し、レイヤーとして自分(キーテストシーン)に追加し、 Director::getInstance()->replaceScene(this); を呼んで自分を有効にしている。
やっていることは単純。テストレイヤー(KeyboardTest)を持った、テストレイヤー(KeyboardTestScene)を有効にし、 キーハンドラを登録し、ハンドラが呼ばれたら内容をログに出力しているだけだ。
いまいちよくわからないのは、retain(), release() を呼んでいる部分。これが本当に必要なの? cocos2d-x 仕様の不備のような気がしないでもない。