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