
上図のテストプログラム画面で、「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 仕様の不備のような気がしないでもない。