quick-cocos2dx 懸浮節點(NotificationNode)

cocos2dx 開發遊戲時,有時某些節點不須要隨着場景的切換而銷燬。但cocos2dx的機制只容許同時只有一個運行的場景,若是你的全部節點都是依附於這個場景的,那場景的切換必然帶來節點的銷燬。node

好比,咱們有一個懸浮圖標,用來設置音樂音量,不管哪一個場景都須要有這個按鈕。就可使用NotificationNode。服務器

我遇到的問題是,收到服務器來的一條消息,客戶端作一個提示,同時場景作一個切換。這就勢必產生問題:提示文字首先加入到了要被銷燬的場景,很快,新場景產生,就場景銷燬,這個過程很短暫,因此你根本沒法看到文字提示,就以爲莫名其妙切換了場景。app

目前解決方法是收到這個提示消息後,延遲3秒鐘顯示,以保證場景已經切換完成。但以爲這個方法很不高大上,既然我有這個需求,別人確定也會有,那麼cocos自己就已經會提供更好的解決方法。ide

 

因而仔細查看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);

 

如今就完美啦。性能神馬的會不會有什麼影響,只能後續測試啦。ui

相關文章
相關標籤/搜索