Memorandum

自分へのメモ。そして誰かの役に立てば、うれしい。

cocos2d-xでゲームを作ろう! 第十回 キャラクタを動かそう2編

さて、前回は結構自信満々だったんですが、あえなく撃沈。
まぁ、プログラムにバグはつきものということで、調査してみましょう。

コールスタックを確認しよう!

さて、エラーの内容は、以下の箇所の「m_pActionManager」がNULLということなんですが。。。
このCCNodeがどこかで解放されたということでしょうか?


さて、コールスタックはどうなっているのでしょう。以下、通りです。
「void Human::walkRamdom(void)」が動作していることから考えると、移動のアニメーションの契機で問題が発生しているようですね。
f:id:Keizi:20131005164335p:plain

「pSprite->runAction(pAction)」の呼び出しがまずいようですねー。

まっさきに思いつくのは、pSpriteがリリースされていると思いますよね。でも、pSpriteがリリースされているとrunAction()のメソッドもコールできないでしようし。
まず、このpSpriteのアドレス以下のメソッド毎に出力させてみました。

Cocos2d: Human::addParent pSprite 0xb451ed0
Cocos2d: Human::addParent pSprite 0xb452c20
Cocos2d: Human::addParent pSprite 0xb4538d0
Cocos2d: Human::walkRamdom pSprite 0x3f800000

あ!なんか、Human::walkRamdom()の時のpSpriteのアドレスが違う。。。今回、3つのキャラクタを登録しているので、Human::addParentが3回コールされるのは想定通りです。その後のHuman::walkRamdom()で表示されるpSpriteは、このうちのどれかになるはずですが、うーん。
そもそも、このHuman::walkRamdom()は、どのインスタンスからコールされているのでしょう。

では、thisポインタのアドレスを表示してみましょう。

Cocos2d: Human::addParent this 0x9e84510
Cocos2d: Human::addParent this 0x9e93340
Cocos2d: Human::addParent this 0x9e93ef0
Cocos2d: Human::walkRamdom this 0x9e84590

やっぱりです。最後にコールされた「Human::walkRamdom()」は、あらかじめ作成したHumanインスタンスのどれでもないです。だれなんでしょう?

Cocos2d: Human::addParent this 0x9b2e720
Cocos2d: Human::addParent this 0x9b3d550
Cocos2d: Human::addParent this 0x9b3e100
Cocos2d: HelloWorld::init() 0x9b2e7a0
Cocos2d: Human::walkRamdom this 0x9b2e7a0

わー!HelloWorldと同じインスタンスのアドレス指しています。どういうこと?「schedule()」は以下のように登録しています。

あっ!schedule()で渡したメソッドは、schedule()を登録したインスタンスからコールされるんですね。。。なるほど。。。

Humanクラスのインスタンス経由で呼び出したい場合は、schedule()はHumanクラスのメソッドをコールしないといけないんですねー。
ということになると、schedule()はCCNodeのメソッドだから、HumanクラスはCCNodeを継承しないといけませんね。

では、早速修正!

まずは、CCNodeを継承して、schedule()の呼び出しをHumanクラスのインスタンス経由にするように修正します

さぁ、どうだ!

ん、あれ、落ちなくはなったけど、移動してくれません。
あ、cocos2d-xはシーンノードで構築されているから、schedule()の呼び出しもシーンとの関連がないと動かないのかもしれません。
今は、Humanは、どのシーンとも関連をもっていません。では、シーンにHumanインスタンスを登録しましょう。

歩いたよ〜

f:id:Keizi:20131005180116p:plain