読者です 読者をやめる 読者になる 読者になる

情報は力ではない

VimとかC++とかCUDAとか。

replaceScene()とEventListener

普段、cocos2dxで開発している訳ではなく、あまりcocos2dxを知らないのだけれど、少し疑問が湧いたのでそれを書いてみる。

疑問: replaceScene()したあと、それまでに登録していたEventListenerはどうなるのか

例えば、あるシーンをタッチすると次のシーンに移る、というようなことをしたいとき
次のように書くことが出来ると思う。

bool AScene::init() {
  // ...
  auto listener = EventListenerTouchOneByOne::create();
  listener->onTouchBegan = [this](Touch* touch, Event* event) {
    Director::getInstance()->replaceScene(AnotherScene::create());
  }
  this->getEventDispatcher()->
    addEventListenerWithSceneGraphPriority(listener, this);
  // ...

画面をタッチして次のシーンに移ったあとでもEventDispatcherに登録しているEventListenerは
EventDispatcherの中にまだ残っているのではないかと思う。
replaceScene()するときには手動でEventListenerを削除しないといけないのかなと思いながら
documentを読んでみるとちゃんと書いてた。

EventDispatcher Mechanism | Cocos2d-x

One more thing to keep in mind: if you add a _fixed priority_ listener to a node, you need to remove the listener manually when the node is removed. However, in the case of a _scene graph priority_ listener, the listener is bound to the node: when the node's destructor is called, the listener will be removed automatically.

document曰く、addEventListenerWithFixedPriority()を使う場合、Listenerに対応させたいNodeを削除するときに手動でListenerを消してね。addEventListenerWithSceneGraphPriority()を使う場合はListenerとNodeは対応しているので、Nodeのデストラクタが呼ばれるときに自動的にListenerも削除されるよ。
ってことらしい。なるほど。

上の例でいくとおそらく、replaceScene()をするとASceneのデストラクタが呼ばれ、そのタイミングでASceneに対応づけられたListenerが破棄されるという感じなんだろう。

Nodeの実装を見てみると確かにNodeのデストラクタでEventListenerを削除していた。
https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/2d/CCNode.cpp#L207

_eventDispatcher->removeEventListenerForTarget(this);

ただ、replaceScene()を呼んだからといってすぐにASceneのデストラクタが呼ばれる訳ではないような気がするけど
その辺りはcocos2dxのGCが上手くやってくれているのだろう。

終わりに

今回思ったのは、欲しい情報にヒットするdocumentをすぐに探せるかはわからないんだけど
documentは読みましょうということでした。自分のフローにしておかねば。