• 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);

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

  • 相关阅读:
    【BZOJ1345】[Baltic2007] 序列问题(单调栈大水题)
    【BZOJ2940】[POI2000] 条纹(Multi-SG)
    【BZOJ4589】Hard Nim(FWT+快速幂)
    【CF438E】The Child and Binary Tree(生成函数+多项式开根)
    【洛谷5205】【模板】多项式开根
    【BZOJ4036】[HAOI2015] 按位或(Min-Max容斥+FWT)
    【BZOJ4381】[POI2015] ODW(设阈值+倍增)
    【BZOJ3328】PYXFIB(矩乘+单位根反演)
    【BZOJ2674】Attack(整体二分+树状数组套线段树)
    单纯看懂公式的单位根反演
  • 原文地址:https://www.cnblogs.com/lan0725/p/4682333.html
Copyright © 2020-2023  润新知