ViVi Home > 技術文書 > cocos2d-x > Keyboard テスト


 
Follow @vivisuke Tweet

 

Keyboard テスト
Copyright (C) 2014 by Nobuhide Tsuda

概要

上図のテストプログラム画面で、「Keyboard」を選ぶと、下図のキーボードテスト画面になる。

キーボードテスト画面では、キーを押下・リリースすると、そのキーコードが下図のように出力ウィンドウにログとして表示される。

KeyboardTest.h

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.cpp

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 仕様の不備のような気がしないでもない。