Layer不响应触摸事件

想做的是一个通过鼠标控制小球在屏幕中间弹跳的游戏,代码如下:

bool HelloWorld::init()
{
 //////////////////////////////
 // 1. super init first
    if ( !Layer::init() )
    {
 return false;
    }
 
 size = Director::getInstance()->getVisibleSize();
 
 printf("size.width=%f, size.height=%f\n", size.width, size.height);
 
 world = new b2World(b2Vec2(0, 0));
 
 world->SetContactListener(this);
 
//    addBackGround();


 
    addEdge();


    addBall();
 
//    onEnter();
 
 scheduleUpdate();


 return true;
}


void HelloWorld::onEnter(){
 printf("onEnter!\n");
 
    Layer::onEnter();
 
 this->setTouchEnabled(true);
}


void HelloWorld::update(float dt){
 
    world->Step(dt, 8, 3);


    for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()){
        if(b->GetUserData() == sBall){
            sBall->setPosition(b->GetPosition().x*RATIO, b->GetPosition().y*RATIO);
//            printf("x=%f, y=%f\n", b->GetPosition().x, b->GetPosition().y);
        }
    }
}


void HelloWorld::onTouchesBegan(Touch *t, Event *e){
 
    auto location = t->getLocationInView();
    location = CCDirector::getInstance()->convertToGL(location);
 
    auto locationWorld = b2Vec2(location.x/RATIO, location.y/RATIO);
 printf("onTouchesBegin, locationWorld.x=%f, locationWorld.y=%f\n", locationWorld.x, locationWorld.y);
    if(ball->GetFixtureList()->TestPoint(locationWorld)){
 b2MouseJointDef md;
        md.bodyA = ball;
        md.bodyB = edgeBody;
        md.target = locationWorld;
        md.collideConnected = true;
        md.maxForce = 1000.0f * ball->GetMass();
 
 mouseJoint = (b2MouseJoint *)world->CreateJoint(&md);
        flag = true;
 printf("onTouchesBegin, I'm in!\n");
    }
 
 return;
}


void HelloWorld::onTouchesMoved(Touch *t, Event *e){
    if(mouseJoint == NULL || flag == false) return;
 
    auto location = t->getLocationInView();
    location = CCDirector::getInstance()->convertToGL(location);
 
    auto locationWorld = b2Vec2(location.x/RATIO, location.y/RATIO);
 
    mouseJoint->SetTarget(locationWorld);
 
 return;
}


void HelloWorld::onTouchesEnded(Touch *t, Event *e){
    if(mouseJoint != NULL && flag == true){
 world->DestroyJoint(mouseJoint);
        mouseJoint = NULL;
        flag = false;
    }
 return;
}


运行效果是无法响应触摸事件(即不能输出onTouchesBegin那的LOG), 在网上查了很多例子,没有看出有什么差别,希望得到大神的解答。

if(ball->GetFixtureList()->TestPoint(locationWorld)){

你的这个语句成功了吗?

问题排查方法:

  1. 首先检查ccTouchBegan是否进入
  2. 查看locaitonWorld的值是多少
  3. 查查TestPoint的文档,看看这个函数需要什么样的参数。打个断点,跟进去看看就知道问题了。
  1. 首先检查ccTouchBegan是否进入

事实上,那个onTouchBegan()方法没有进入
因为65行的 printf(“onTouchesBegin, locationWorld.x=%f, locationWorld.y=%f\n”, locationWorld.x, locationWorld.y);在屏幕上没有输出。

所以那个if语句自然也没有进入了,我刚刚开始学习,不知道该如何debug,在点击屏幕后我该在哪个函数里面增加断点才能一步一步排查出为什么最后没有调用onTouchBegan呢?

解决了一半问题,但是还是没有好的解决办法,同时对问题出现的根本原因十分不理解。

通过单步调试,发现当产生触摸事件之后,调用的onTouchesBegan()方法为Layer::onTouchesBegan();
并没有调用我在HelloWorld中重写的onTouchesBegan()方法,所以就没有LOG输出也没有响应。

所以目前想到的解决办法是不使用setTouchEnabled方法,而是自己注册EventListener。

问题虽然可以解决,但是既然有setTouchEnabled方法,就应该是可以调用重写的onTouch方法啊,不是很理解,我再想一想。

想请教一下,如何配置调试环境的?是用eclipse调试C++代码么?

visual studio就可以调试啊。
在setTouchEnabled(true)以后
你忘了调用setTouchMode(TouchDispatchMode::AllAtOnce)了。

呃,VS下是可以调试,但是转成APK之后,我还想在android机器上调试,这个怎么弄了?只能用cclog么?

你忘了调用setTouchMode(TouchDispatchMode::AllAtOnce)了。
默认的TouchMode就是AllAtOnce,所以不用设置。而且设置的我也试过了。
代码修正为setTouchEnabled(true)就可以响应点击了,不过现在拖动还是问题。。

不好意思。。我是在xcode下开发的,所以对于别的平台怎么配置一点都不懂,帮不上你了,sorry~

android可以用#define LOGD(…) __android_log_print(ANDROID_LOG_DEBUG,"",VA_ARGS)来调试,代码里面用LOGD就可以了。

setTouchMode() 这个已经deprecated的了吧 用eventdispatcher,这个是新的引擎支持的…

拖动的话可以参考
void GameMain::onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event)
{
Touch *pTouch = touches;

m_tOffset.x = pTouch->getLocation().x - m_ptHero->getPositionX();
m_tOffset.y = pTouch->getLocation().y - m_ptHero->getPositionY();

}

void GameMain::onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event)
{
Touch *pTouch = touches;

Size tSize = Director::getInstance()->getWinSize();
Vec2 tEndPoint = pTouch->getLocation();
float fMoveToX = tEndPoint.x - m_tOffset.x;
float fMoveToY = tEndPoint.y - m_tOffset.y;

float fMinPositionX = m_ptHero->getContentSize().width * m_ptHero->getScaleX() * 0.5;
float fMaxPositionX = tSize.width - fMinPositionX;

float fMinPositionY = m_ptHero->getContentSize().height * m_ptHero->getScaleY() * 0.5;
float fMaxPositionY = tSize.height - fMinPositionY;

if (m_tOffset.x < 0)
{
    m_ptHero->getLeftHand()->setFlippedY(true);
    m_ptHero->getRightHand()->setFlippedY(false);
}
else 
{
    m_ptHero->getLeftHand()->setFlippedY(false);
    m_ptHero->getRightHand()->setFlippedY(true);
}
 
fMoveToX = GameMain::reviseNumberForRange(fMoveToX, fMinPositionX, fMaxPositionX);
fMoveToY = GameMain::reviseNumberForRange(fMoveToY, fMinPositionY, fMaxPositionY);

m_ptHero->setPosition(Vec2(fMoveToX, fMoveToY));

}

void GameMain::onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event)
{
Touch *pTouch = touches;
m_ptHero->getLeftHand()->setFlippedX(false);
m_ptHero->getRightHand()->setFlippedX(false);
}

直接用log(“your message”, …)就可以了吧,win下和android都可以显示你的信息

— Begin quote from ____

引用第11楼低调kepler于2014-09-01 16:18发表的 回 6楼(燃烧吧-脂肪) 的帖子 :
直接用log(“your message”, …)就可以了吧,win下和android都可以显示你的信息 http://www.cocoachina.com/bbs/job.php?action=topost&tid=226229&pid=1043629

— End quote

嗯,这样可以的,我现在也是这样在调试。不过还是希望能够用debugger能够一步一步的跟踪调试,这样能方便很多O(∩_∩)O哈哈~