zoukankan      html  css  js  c++  java
  • quick-cocos2dx 悬浮节点(NotificationNode)

    cocos2dx 开发游戏时,有时某些节点不需要随着场景的切换而销毁。但cocos2dx的机制只允许同时只有一个运行的场景,如果你的所有节点都是依附于这个场景的,那场景的切换必然带来节点的销毁。

    比如,我们有一个悬浮图标,用来设置音乐音量,无论哪个场景都需要有这个按钮。就可以使用NotificationNode。

    我遇到的问题是,收到服务器来的一条消息,客户端做一个提示,同时场景做一个切换。这就势必产生问题:提示文字首先加入到了要被销毁的场景,很快,新场景产生,就场景销毁,这个过程很短暂,所以你根本无法看到文字提示,就觉得莫名其妙切换了场景。

    目前解决方法是收到这个提示消息后,延迟3秒钟显示,以保证场景已经切换完成。但觉得这个方法很不高大上,既然我有这个需求,别人肯定也会有,那么cocos本身就已经会提供更好的解决方法。

    于是仔细查看Scene的C++代码,最终在Director的drawScene方法中,发现了这个片段

     // draw the scene
        if (_runningScene)
        {
            _runningScene->visit(_renderer, Mat4::IDENTITY, false);
            _eventDispatcher->dispatchEvent(_eventAfterVisit);
        }
    
        // draw the notifications node
        if (_notificationNode)
        {
            _notificationNode->visit(_renderer, Mat4::IDENTITY, false);
        }
    _notificationNode 是一个亮点,于是各种百度google之后,觉得这才是最王道的解决方法。

    于是我在quick中是这样调用的,myapp.lua 的ctor 方法 增加 如下代码:
    cc.Director:getInstance():setNotificationNode(require("app.views.NotificationLayer").new())
    NotificationLayer 源码是这样的
    --
    -- Created by IntelliJ IDEA.
    -- User: Elan
    -- Date: 15-7-27 下午5:37
    -- To change this template use File | Settings | File Templates.
    --
    
    local NotificationLayer = class("NotificationLayer", function()
        return display.newNode()
    end)
    
    function NotificationLayer:ctor()
        self:setNodeEventEnabled(true)
        self:addSprite()
        self:hide()
    end
    
    function NotificationLayer:registerNotificationCenter()
        self.showNotificationHandle = GameDataCenter:addEventListener("showNotification", handler(self, self.showAni))
    end
    
    function NotificationLayer:unregisterNotificationCenter()
        GameDataCenter:removeEventListener(self.showNotificationHandle)
    end
    
    
    function NotificationLayer:onEnter()
        self:registerNotificationCenter()
        print("onEnter..............")
    end
    
    function NotificationLayer:onExit()
        self:unregisterNotificationCenter()
        print("onExit..............")
    end
    
    function NotificationLayer:addSprite()
        self.bg = cc.ui.UIImage.new("#images/common/ui/shangfangtishi.png")
        :align(display.BOTTOM_CENTER, display.cx, display.top)
        :addTo(self)
    
        self.bgw = self.bg:getContentSize().width
        self.bgh = self.bg:getContentSize().height
    
        self.txtLabel = cc.ui.UILabel.new({
            text = "",
            size = 24,
            color = ccYELLOW,
            align = ui.TEXT_ALIGN_CENTER
        })
        :align(display.CENTER, self.bgw/2, self.bgh/2)
        :addTo(self.bg)
    end
    
    function NotificationLayer:showAni(data)
        self.bg:stopAllActions()
        self:show()
        local msg = data.Responsedata
        self.txtLabel:setString(msg)
        local action = transition.sequence({
            cc.MoveTo:create(0.5, cc.p(display.cx, display.top - self.bgh)),
            cc.DelayTime:create(2),
            cc.MoveBy:create(0.1, cc.p(display.cx, display.top)),
            cc.CallFunc:create(function()
                self:hide()
            end)
        })
        self.bg:runAction(action)
    end
    
    return NotificationLayer
    我在其他地方触发 showNotification 事件后,发现背景板并没有顺利的移动出来,就是说我的action并没有执行成功。于是单步调试,发现runAction调用时,node本身的_running是false,所以action并没有执行。
    看网上很多童鞋说再调用一下onEnter方法,确实是,只有onEnter方法里面_running才会被设置为true。于是我在lua里面调用onEnter,真是笨到家了。因为lua里面的onEnter是C++里面的onEnter的回调,所以啥作用都没起。

    于是我在Director里面增加调用onEnter()方法,然后很成功的执行了action。
    void Director::setNotificationNode(Node *node)
    {
        CC_SAFE_RELEASE(_notificationNode);
        _notificationNode = node;
        node->onEnter(); //  add by Elan 2015.7.27
        CC_SAFE_RETAIN(_notificationNode);
    }

    但是,我关掉player的时候,又报错了:

    Node still marked as running on node destruction! Was base class onExit() called in derived class onExit() implementations?

    C++一看,node的析构函数报错,node 的_running 为true的时候销毁这个node就会报这个错。_running只在OnExit()的会被设为false。于是我在Director 的析构函数中又增加了一句。部分代码如下。

    Director::~Director(void)
    {
        CCLOGINFO("deallocing Director: %p", this);
    
        if (_notificationNode)
        {
            _notificationNode->onExit(); // add by Elan 2015.7.27
        }
    
        CC_SAFE_RELEASE(_FPSLabel);
        CC_SAFE_RELEASE(_drawnVerticesLabel);
        CC_SAFE_RELEASE(_drawnBatchesLabel);
    
        CC_SAFE_RELEASE(_runningScene);
        CC_SAFE_RELEASE(_notificationNode);
        CC_SAFE_RELEASE(_scheduler);
        CC_SAFE_RELEASE(_actionManager);
    
        CC_SAFE_RELEASE(_scriptEventCenter);

    现在就完美啦。性能神马的会不会有什么影响,只能后续测试啦。

  • 相关阅读:
    Java实现 LeetCode 56 合并区间
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    JQuery实现对html结点的操作(创建,添加,删除)
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 55 跳跃游戏
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
    Java实现 LeetCode 54 螺旋矩阵
  • 原文地址:https://www.cnblogs.com/lan0725/p/4682333.html
Copyright © 2011-2022 走看看