レイヤーのタッチイベントについて質問があります。
ゲーム画面上にはプレイヤーがいて、プレイヤーを動かすアナログキーがあります。
アナログキーを押すと、プレイヤーが動き、アナログキー以外の場所を押すと、メニュー画面を呼び出すなどの別のタッチイベントを
実装したいと思っています。
アナログキーの実装はweb上にあったsneakyButtonというクラスで実装しています。タッチイベント全体を管理するクラスInputLayer(CCLayerを継承)を用意し、InputLayerにsneakyButtonを貼付けています。(addchild)
以下にInputLayerとsneakyButtonの簡単な構造を示します。
--------------------sneakyButton.cpp-------------------------
void SneakyButton::onEnterTransitionDidFinish()
{
//十字キーの方がInputLayerよりタッチイベントの優先度を高くしています
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -100, true);
}
void SneakyButton::onExit()
{
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}
//省略
bool SneakyButton::ccTouchBegan(CCTouch *touch, CCEvent *event)
{
CCLOG("十字キーが押されました");
//ボタンが押されている状態ならタッチ始めの処理はしません
if (active) return false;
CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->getLocationInView());
location = this->convertToNodeSpace(location);
//Do a fast rect check before doing a circle hit check:
if(location.x < -radius || location.x > radius || location.y < -radius || location.y > radius){
//①十字キー以外の場所がタッチされました。本レイヤーよりタッチイベントの優先度が低いレイヤー(InputLayer)にタッチイベントが移行します。
return false;
}else{
float dSq = location.x*location.x + location.y*location.y;
if(radiusSq > dSq){
//②十字キーをアクティブ化します
active = true;
if (!isHoldable && !isToggleable){
value = 1;
this->schedule(schedule_selector(SneakyButton::limiter), rateLimit);
}
if (isHoldable) value = 1;
if (isToggleable) value = !value;
return true;
}
}
return false;
}
--------------------------InputLayer.cpp--------------------------------
void InputLayer::onEnter()
{
//sneakyButtonより1つ優先度が低いです。十字キー以外の場所が押されたら、本レイヤーのタッチイベントが実行される。
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -99, true);
}
void InputLayer::onExit()
{
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}
bool InputLayer::init()
{
if (!CCLayer::init()) {
return false;
}
//タイマーセット
this->scheduleUpdate();
//======================================================================
// 十字キーの部分です
//======================================================================
//==========================各種ボタンをインスタンス化します============================
UpButton = new SneakyButton();
UpButton->initWithRect(CCRectZero);
UpButton->setIsToggleable(false);
UpButton->setIsHoldable(true);
UpButton->setRadius(40.0);
UpButton->setTag(0);
UpButton->autorelease();
//=======================================================
SneakyButtonSkinnedBase *ButtonBase1 = SneakyButtonSkinnedBase::create();
UpButton->init();
ButtonBase1->setButton(UpButton);
ButtonBase1->setDefaultSprite(CCSprite::create("UpArrow.png")); //通常時の画像
//ButtonBase->setDisabledSprite(CCSprite::create("UpArrow.png"));
ButtonBase1->setActivatedSprite(CCSprite::create("UpArrowSelected.png")); //押しっぱの時の画像
ButtonBase1->setPressSprite(CCSprite::create("UpArrowSelected.png")); //押し始めの画像
ButtonBase1->setPosition(ccp(200, 200));
this->addChild(ButtonBase1);
//以下同様、十字キーのボタンの分、sneakyButtonをインスタンス化します
return true;
}
//このタイマーは十字キーが押されたかどうか常に監視しています
void InputLayer::update(float delta)
{
//省略
if (UpButton->getIsActive()) {
CCLOG("上に行きます");
//プレイヤーを押された方向に動かす処理
}else if (DownButton->getIsActive()){
CCLOG("下に行きます");
//プレイヤーを押された方向に動かす処理
}else if (RightButton->getIsActive()){
CCLOG("右に行きます");
//プレイヤーを押された方向に動かす処理
}else if (LeftButton->getIsActive()){
CCLOG("左に行きます");
//プレイヤーを押された方向に動かす処理
}
}
bool InputLayer::ccTouchBegan(cocos2d::CCTouch *touch, cocos2d::CCEvent *event)
{
CCLOG("十字キー以外の場所がタッチされたので、メニュー画面を呼び出すなどの処理をします");
return true;
}
以上になります。
実現しようとしているプログラムの流れを説明します。
InputLayerで十字キーが押されたかどうかをupdate関数で監視しています。押されたかどうかの判断は、sneakyButtonクラスのメンバ変数activeがtrueになったかどうかで判断しています、十字キーが押された場合、activeはtrueになりますので、update関数で十字キーが押されたと判断できるようになります。
次に、十字キー以外の場所をタッチされたとき、別のタッチイベントを発生させたいのです。(例えば、別のキャラクターの前でタッチしたら、会話が始まったり、またはメニュー画面を呼び出したりなど)。
そこで、まずsneakyButtonクラスのccTouchBegan関数内で、十字キー以外の場所が押されたと判断したら、falseを返します。そうしましたら、レイヤーのタッチイベントの優先度が次に高いInputLayerにタッチイベントが移行して、InputLayer内のccTouchBegan関数内で、別のタッチイベントを発生するという流れです。
これを実現しようとしたのですが、コンソールを見ると、まず十字キー以外の場所をタッチしたらsneakyButtonクラスでfalseを返し、InputLayerのccTouchBegan関数内に入ったところまでは確認できました。
ですが、十字キーを押したら、sneakyButtonクラスの②の部分まで入り、変数activeもtrueになっているのは確認できたのですが、InputLayer内のupdate関数でどうやらactiveがtrueになっていない様なのです。なので、キャラクターが動かず困っています。
試しに、InputLayerのタッチイベントを消して、sneakyButtonのみのタッチイベントで実行したら、キャラクターは動きました。
いったいどこに原因があるのでしょうか?