关于不同Layer之间消息的传递

  • 本帖最后由 jetion 于 2012-10-2 19:24 编辑 *

我遇到的情况是这样的,有两个Layer,一个是GestureLayer,也就是识别手势的层;还有一个是PlayLayer,就是游戏层。在我的GestureLayer接收到相关的手势事件时,我想让PlayLayer上实现某些动画等。
现在我的问题是:PlayLayer怎么知道GestureLayer触发手势事件了。
目前我的想法:1.就是设置标志位,当GestureLayer接收到手势事件时,给标志位true;然后在PlayLayer中不断检测该标志位,若检测到true,就执行相应的动画,然后马上把该标志位false。
2.就是设置一个监听,写一个接口,假设为 GestureLayerDelegate ,里面有相关手势触发后执行的函数,然后让PlayLayer继承它,并复写相关函数,在GestureLayer中定义一个 GestureLayerDelegate * delegate;的对象,在GestureLayer中触发手势事件时,用delegate来调用PlayLayer中的重写的接口函数。我遇到的问题就是:手势触发时,delegate调用PlayLayer中重写的接口函数是没问题的,我用CCLog打印了,是有执行的,但是我在接口函数中写的一句sprite->runAction()并没有执行,sprite是我在PlayLayer中添加的精灵,这是什么回事呢?

class GestureLayerDelegate
{
public:
        virtual void onGestureRun()=0;
    virtual void onGestureBack()=0;
    virtual void onGestureUpOne()=0;
        virtual void onGestureUpTwo()=0;
    virtual void onGestureDown()=0;
};

#endif
class PlayLayer :public CCLayer, public GestureLayerDelegate
{
private:
        NormalPerson* nPerson;
public:
        PlayLayer(void);
        ~PlayLayer(void);
        virtual bool init();
        void update();
        virtual void onGestureRun();
    virtual void onGestureBack();
    virtual void onGestureUpOne();
        virtual void onGestureUpTwo();
    virtual void onGestureDown();
};
class GestureLayer : public CCLayer
{
private:
        GestureLayerDelegate* delegate;
}

在touch事件中执行
delegate->onGestureUpOne();

如果可以的话,帮忙讲解一下监听和委托的原理,万分感谢!!

  • 本帖最后由 reckhou 于 2012-10-9 20:41 编辑 *

在GestureLayer中定义一个 GestureLayerDelegate * delegate;的对象

你的问题出在这里,如果这样调用的话,实际上还是调用GestureLayerDelegate 这个接口类里的方法,而不是你在派生类中重定义后的方法。

实际上调用的时候应该这样:(示例代码随便乱写的)

PlayLayer *object = new PlayLayer();
object->onGestureRun(); // 这样调用的才是在派生类中重定义的方法

如果这样的话是错误的:

GestureLayerDelegate *object = new GestureLayerDelegate();
object->onGestureRun();

好吧…应该就是这个问题,新手对C++语言特性还不熟,呵呵

  • 本帖最后由 jetion 于 2012-10-10 09:24 编辑 *

首先,第一个种用update的实在有点繁琐,抛弃了。
第二种,找了很久的资料,一直没找到C++实现委托的方法,网上有说C++本身不支持委托的(本人是C++菜鸟,正在努力学习中)。最后,两种都没使用了。
最后,我的解决方法:就是使用监听。类似java的。
1.创建一个接口

class GestureCallBack
{
public:
        virtual void onGestureTrigger(GestureType type) =0;
};

2.在PlayLayer层重写这个接口
3.在GestureLayer层中定义一个GestureCallBack *callBack的对象,并且该层得有一个初始化该对象的函数

class GestureLayer : public CCLayer
{        
public:
        GestureCallBack* gestureCallBack;
        void registerGestureCallBack(GestureCallBack* gcb);
void GestureLayer::registerGestureCallBack(GestureCallBack* gcb)
{
        CCLog("registerGestureCallBack");
        gestureCallBack = gcb;
}

按照类似MVC的原则,我们是不能从这个层直接调用另一个层的东西的,比如,我不能直接从PlayLayer层调用GestureLayer层的registerGestureCallBack(GestureCallBack* gcb)方法的,我应该再创建一个GloballManager的类,它是一个单例模式的类,是作为PlayLayer和GestureLayer沟通的桥梁,它负责包括PlayLayer和GestureLayer等游戏层的逻辑控制,它里面应该包含所有层的控制权限,包括start、stop、resume等方法。比如,我按了游戏的暂停按钮,我在GloballlManager层里面应该把PlayLayer层、GestureLayer层Stop了,而可能有一些dialog等层,它们应该Start。还有就是,可能我要在GestureLayer里面调用PlayLayer层里面的东西,我可以通过GloballlManager::getInstance()单例对象来获取GloballlManager里面声明好的PlayLayer层的对象,从而我就通过它来调用PlayLayer层里面的东西了。当然,它们应该都在一个Controller层里面先初始化好,这个层是作为整个场景的父容器,它包含了PlayLayer和GestureLayer等游戏相关的层,并且这些层都在它上面进行了初始化,它的作用就是负责整个游戏场景的生活周期的控制,以及游戏中所有该准备的东西,所有的初始化。
GameController中初始化:

bool GameController::init()
{
        pl = new PlayLayer();
        this->addChild(pl);
        gl = new GestureLayer();
        this->addChild(gl, 1);
        GloballManager::getInstance()->gestureLayer = gl;
        GloballManager::getInstance()->playLayer = pl;
        GloballManager::getInstance()->gestureLayer->registerGestureCallBack(pl);
        scheduleUpdate();
        return true;
}

GloballlManager单例对象:

class GloballManager
{
private:
        GloballManager(void);
        static GloballManager* s_GloballManager;
public:
        PlayLayer* playLayer;
        GestureLayer* gestureLayer;
        ~GloballManager(void);
        void init();
        static GloballManager* getInstance();
        
};

这样,我只要在GestureLayer中手势触发的地方,使用gestureCallBack调用PlayLayer中重写的onGestureTrigger(GestureType type)方法即可。

PS:这个问题的关键不是gestureCallBack得用new PlayLayer()来初始化,也不是PlayLayer里面重写的接口方法未实现。
真正的原因是,PlayLayer这个层的指针没给对,
之前我一直实在GestureLayer里面直接初始化gestureCallBack的,用到下面这么一句代码:
gestureCallBack = new PlayLayer();
这么写是没错的,它也成功初始化了,但是这边有一个很明显,也很容易让想我这种新手忽略的问题,就是我在GameController中有这么一句话:pl = new PlayLayer();并且我把pl添加到我的游戏场景中了,也就是说,此时我整个游戏场景中,其作用的应该是pl这个层。问题来了,我又在GestureLayer中初识化了一个gestureCallBack,而它并没有添加到我的GameController中,也就是我的游戏场景中,所以,我对它的一切操作都无法正常显示。
也就是因为这样,我们在GestureLayer中需要一个函数接口来往外传gestureCallBack,也就是registerGestureCallBack(GestureCallBack* gcb)这个函数,而我只要在GameController中调用这个函数,并把pl往里传就行了。
总结起来就是一句话,整个游戏只有一个PlayLayer层,也只有一个GestureLayer层,一切操作都应该是作用到它们身上的,所以,我们也可以在GameController中把它们定义为静态对象!

可能我描述得有点不清楚了。其实我最终是想解决这个问题:
我有两个Layer,一个是GestureLayer,是识别手势的,在上面;还有一个是PlayLayer,是游戏层,在下面。现在我要在GestureLayer中识别手势,然后把消息实时传递给PlayLayer,让里面的相应的人物做出相应的动作。

  • 本帖最后由 jetion 于 2012-10-10 09:00 编辑 *

— Begin quote from ____

reckhou 发表于 2012-10-9 20:40 url

在GestureLayer中定义一个 GestureLayerDelegate * delegate;的对象

你的问题出在这里,如果这样调用的话 …

— End quote

我忘了把这句代码给出来了
GestureLayerDelegate* delegate = new PlayLayer();
我是这么实例化的,就像你所说的,GestureLayerDelegate是一个抽象类,没理法直接实例化的,要通过其子类来声明一个对象。
我这个问题的关键就是:new PlayLayer()这个对象指针没给对,就像我前面说的,我PlayLayer是在GameController里面初始化并添加的,在那边我就已经new了一个对象了,然后后面在GestureLayer这边又new了一个对象,而此对象并没有添加到我的游戏场景中,导致我对PlayLayer层中的任何操作都不管用。我应该赋给delegate的应该是我添加到游戏场景中的PlayLayer的指针!