日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

从此之后,Creator 再无秘密

發(fā)布時(shí)間:2024/5/14 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从此之后,Creator 再无秘密 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在一位Cocos資深開(kāi)發(fā)者的Creator 之旅(上)這篇文章里,我們的老朋友SuperSuRaccoon深入淺出地把Creator 分析了透透底底,一點(diǎn)小秘密都沒(méi)給我們留。今天,這個(gè)精彩的旅程將繼續(xù)走下去。


Part.4 邏輯樹(shù) vs 渲染樹(shù)

初看 CCC 的文檔,一個(gè)比較新的概念,就是 邏輯樹(shù) vs 渲染樹(shù),當(dāng)然這也是比較讓人迷惑的概念。但是在我們有了上面這些知識(shí)的積累之后,就可以比較好的來(lái)理解這個(gè)意義了。

渲染樹(shù)

在過(guò)去的 cocos2d-js 中,我們?cè)趧?chuàng)建一個(gè)游戲場(chǎng)景的時(shí)候,通常是這樣一個(gè)步驟(就拿最簡(jiǎn)單的,自帶的 HelloWorld 舉例):

// 首先要有一個(gè) Scene var HelloWorldScene = cc.Scene.extend({onEnter:function () {this._super();var layer = new HelloWorldLayer();this.addChild(layer);} });// 其次是這個(gè) Scene 中的一個(gè) Layer var HelloWorldLayer = cc.Layer.extend({ctor:function () {this._super();// ...var helloLabel = new cc.LabelTTF(/*...*/);this.addChild(helloLabel);// this.sprite = new cc.Sprite(/*...*/);this.addChild(this.sprite);} });// 最后,是在啟動(dòng)的時(shí)候,運(yùn)行這個(gè) Scene cc.game.onStart = function(){// ...cc.director.runScene(new HelloWorldScene()); }; cc.game.run();

這是一個(gè)非常經(jīng)典,簡(jiǎn)單的,啟動(dòng)流程。 對(duì)于這樣一個(gè)例子,在實(shí)際生成的場(chǎng)景中,渲染樹(shù)的內(nèi)容是這樣的 :

+ Canvas (游戲渲染在瀏覽器的一個(gè) Canvas 標(biāo)簽中)+ CCScene+ CCLayer- CCSprite : HelloWorld.png- CCLabelTTF: "HelloWorld"

再來(lái)看官方的解釋就很好理解了 :

在cocos2d-js中,渲染器會(huì)遍歷場(chǎng)景節(jié)點(diǎn)樹(shù)來(lái)生成渲染隊(duì)列,所以開(kāi)發(fā)者構(gòu)建的節(jié)點(diǎn)樹(shù)實(shí)際上就是渲染樹(shù)。

我們創(chuàng)建的 cc.Scene,cc.Layer,cc.Sprite,cc.LabelTTF 這些節(jié)點(diǎn)構(gòu)成的樹(shù),直接就是渲染樹(shù)。

邏輯樹(shù)

在 CCC,中 邏輯樹(shù) 的概念被添加了進(jìn)來(lái),官方的解釋中,有這幾點(diǎn)很重要 :

開(kāi)發(fā)者在編輯器中搭建的節(jié)點(diǎn)樹(shù)和掛載的組件共同組成了邏輯樹(shù) 節(jié)點(diǎn)構(gòu)成實(shí)體單位,組件負(fù)責(zé)邏輯 邏輯樹(shù)關(guān)注的是游戲邏輯而不是渲染關(guān)系, 邏輯樹(shù)會(huì)生成場(chǎng)景的渲染樹(shù),決定渲染順序,開(kāi)發(fā)者并不需要關(guān)心這些。

第1,2點(diǎn),編輯器中添加到節(jié)點(diǎn),其實(shí)都是 cc.Node 對(duì)象,我們已經(jīng)知道,它只是一個(gè)空殼,一個(gè)容器,雖然持有了過(guò)去 cc.Node 的基礎(chǔ)屬性,和方法,它并不負(fù)責(zé)任何渲染的任務(wù)。 同樣的,在它身上掛載的這些組件,都繼承自 cc.Component ,即使是繼承自 cc.SGComponent 的組件,也并不是直接負(fù)責(zé)渲染的,負(fù)責(zé)渲染的,是背后對(duì)應(yīng)的 _ccsg.Xxx 對(duì)象們。

第3,4點(diǎn),邏輯樹(shù)關(guān)注的是游戲邏輯,不是渲染關(guān)系,因?yàn)?CCC 已經(jīng)將渲染的細(xì)節(jié)進(jìn)行了隱藏,我們?cè)诰庉嬈髦兄皇秦?fù)責(zé)將一些節(jié)點(diǎn)的順序進(jìn)行組織,對(duì)于那些需要渲染的節(jié)點(diǎn)中的組件,CCC 會(huì)將這些邏輯樹(shù)上的節(jié)點(diǎn),翻譯成一顆渲染樹(shù),在幕后,就像過(guò)去一樣,為我們渲染出一個(gè)游戲世界來(lái)。

渲染樹(shù)的生成

既然 CCC 會(huì)為我們自動(dòng)生成想過(guò)去一樣的渲染樹(shù),那么它究竟是怎么做到的呢。 同樣的,拿一個(gè)簡(jiǎn)單的 CCC 的 HelloWorld,來(lái)做例子。 注意,這里為了簡(jiǎn)化例子,刪除了原本 cc.Scene 中自帶的 cc.Canvas 節(jié)點(diǎn),以及一個(gè)背景節(jié)點(diǎn)。

首先它的起點(diǎn),就和 cocos2d-js 中一樣,在編輯器中需要一個(gè) cc.Scene,接著就是將需要的圖片和文本,以組件掛載節(jié)點(diǎn)的形式,被添加到場(chǎng)景中,它的結(jié)構(gòu)基本上是這樣的 :

+ Canvas (游戲渲染在瀏覽器的一個(gè) Canvas 標(biāo)簽中)+ cc.Scene+ cc.Node (cocos)- Sprite Component- HelloWorld.png+ cc.Node (label)- Label Component- "HelloWorld"

這里所謂的 渲染樹(shù)的自動(dòng)生成 結(jié)合前面,對(duì)于 cc.Node,cc._BaseNode 等一些基礎(chǔ)類(lèi)的分析,其實(shí)可以很容易的理解。 在編輯器中,我們只是不停的重復(fù) 新建節(jié)點(diǎn),掛載組件,新建節(jié)點(diǎn),掛載組件,…… 的操作步驟,以此來(lái)構(gòu)建我們的游戲場(chǎng)景內(nèi)容。

每當(dāng)我們添加一個(gè) cc.Node ,在它的幕后,都會(huì)有一個(gè) _ccsg.Node 被同樣的添加到了場(chǎng)景中,當(dāng)我們添加一個(gè) cc.Sprite 組件,同樣的,一個(gè)用于渲染的節(jié)點(diǎn) cc.Scale9Sprite 被創(chuàng)建,并添加到了之前的 _ccsg.Node 中,這一點(diǎn)在源碼中也有體現(xiàn) :

var RendererUnderSG = cc.Class({extends: require('./CCSGComponent'),ctor: function () {var sgNode = this._sgNode = this._createSgNode();// ...},__preload: function () {// ...this._appendSgNode(this._sgNode);},// ..._appendSgNode: function (sgNode) {var node = this.node;// ...var sgParent = node._sgNode;sgParent.addChild(sgNode);} });

換句話(huà)說(shuō),上面的邏輯樹(shù)的示意圖,其實(shí),在它的幕后,一顆渲染樹(shù),已經(jīng)自動(dòng)的被生成了 :


Part.5 誰(shuí)動(dòng)了我的 cocos2d-js

對(duì)于有 cocos2d-js 經(jīng)驗(yàn)的朋友來(lái)說(shuō),就像本人,需要適應(yīng) CCC 中這種編程理念的轉(zhuǎn)變,同時(shí),也經(jīng)常會(huì)碰到一些自己認(rèn)為這么寫(xiě)理所當(dāng)然正確,但是在 CCC 中卻行不通的情況。 現(xiàn)在,我們有了上面這些知識(shí)的積累,現(xiàn)在該是時(shí)候來(lái)徹底的理解這些過(guò)去一知半解的情況了。

cc.DrawNode

cc.DrawNode 作為 cocos2d-js 中的一個(gè)繪圖類(lèi),使用還是極其廣泛的,尤其對(duì)于本人來(lái)說(shuō),做一些游戲,比起使用 cc.Sprite,更喜歡使用 cc.DrawNode 來(lái)繪制各種圖形內(nèi)容,作為游戲中的元素。此外,利用 cc.DrawNode 來(lái)做游戲中的一些調(diào)試性繪圖,也是非常有用的一種情況。 但是剛接觸 CCC 的時(shí)候,一個(gè)比較困惑的錯(cuò)誤來(lái)自于下面 :

// helloworld.js cc.Class({extends: cc.Component,properties: {},onLoad: function () {var draw = new cc.DrawNode();draw.drawDot(cc.p(0, 0), 20, cc.Color.RED);this.addChild(draw);},});

添加一個(gè) cc.DrawNode,繪制一個(gè)圓,非常簡(jiǎn)單的代碼,卻會(huì)報(bào)錯(cuò) :

Uncaught TypeError: this.addChild is not a function

接著,嘗試著 :

this.node.addChild(draw);

但是同樣會(huì)報(bào)錯(cuò) :

addChild: The child to add must be instance of cc.Node, not _Class.

從報(bào)錯(cuò),可以看出,cc.DrawNode 被成功的創(chuàng)建了,并沒(méi)有提示說(shuō)不認(rèn)識(shí)這個(gè)類(lèi),只是在添加到場(chǎng)景的時(shí)候,出現(xiàn)了各種錯(cuò)誤。 如果在不了解新的 CCC 的設(shè)計(jì)理念的話(huà),這個(gè)問(wèn)題是無(wú)解的, 但是現(xiàn)在我們可以輕松的解決這個(gè)問(wèn)題。


cc.DrawNode Hack

這是一種最最快速的,最最直接的方法,CCC 的論壇也有提到,那就是直接將創(chuàng)建好的 cc.DrawNode 實(shí)例,添加到渲染樹(shù)對(duì)應(yīng)的節(jié)點(diǎn)上 :

this.node._sgNode.addChild(draw);

這就可以正常的在游戲中使用 cc.DrawNode 了?。?

?但是對(duì)于這種方式,官方的說(shuō)明是,這是一種 hack 的方式,并不推薦,因?yàn)楹笃诠俜娇赡軙?huì)禁止 ._sgNode 這種訪問(wèn)方式。

cc.DrawNode Component

好吧,既然這是一種 hack 的方式,不推薦,那我們就自然而然的需要尋找一種合理的方式,迎合 CCC 的設(shè)計(jì)模式,創(chuàng)建一個(gè) cc.DrawNode 的組件,應(yīng)該是最好的解決方案。 首先,這是一個(gè)需要渲染的組件,我們需要它繼承自 cc.SGComponent 中的 cc.RenderUnderSG :

// DrawNodeComponent.js cc.Class({extends: cc._RendererUnderSG, });

緊接著,自然是實(shí)現(xiàn) cc.SGComponent 中的兩個(gè)重要的接口 :

// DrawNodeComponent.js cc.Class({extends: cc._RendererUnderSG,//_createSgNode: function () {return new cc.DrawNode();},_initSgNode: function () {}, });

這里的幕后渲染工作的執(zhí)行者,自然是我們的 cc.DrawNode。 有了實(shí)際的渲染對(duì)象,接下來(lái),就是提供一些方法,給外界調(diào)用,否則外接就需要直接訪問(wèn) ._sgNode 了 :

// DrawNodeComponent.js cc.Class({extends: cc._RendererUnderSG,//_createSgNode: function () {return new cc.DrawNode();},_initSgNode: function () {},//drawDot: function(pos, radius, color) {this._sgNode.drawDot(pos, radius, color);} });

最后,自然就是使用了,在 CCC 編輯器中將這個(gè)組件掛在到節(jié)點(diǎn)上,就可以在腳本中使用了 :

this.getComponent("DrawNodeComponent").drawDot(cc.visibleRect.center, 20, cc.Color.RED );

同樣的結(jié)果,不一樣的實(shí)現(xiàn) :?

當(dāng)然,這里的實(shí)現(xiàn)才是正統(tǒng)的,符合 CCC 的設(shè)計(jì)理念的做法。


cc.Menu && cc.MenuItem

除了上面提到的 cc.DrawNode 外,個(gè)人覺(jué)得 cocos2d-js 中另一個(gè)很有用的類(lèi)就是 cc.Menu,配合 cc.MenuItemFont 之類(lèi)的使用,可以非常快速的創(chuàng)建一個(gè)菜單。 cc.Menu 在 CCC 使用比起上面的 cc.DrawNode 要更復(fù)雜一些,一個(gè)原因在于,它并沒(méi)有被包含到標(biāo)準(zhǔn)生成的引擎文件中 :

cc.log(cc.Menu); // 顯示 undefined

換句話(huà)說(shuō),想要啟用 cc.Menu 就需要將它添加到引擎中。 引擎的定制,可以通過(guò)修改 CCC 中的一個(gè)文件實(shí)現(xiàn) : CocosCreator.app/Contents/Resources/engine/gulp/tasks/modular.js

var modules = {'Core': [// ...'./cocos2d/core/base-nodes/CCSGNode.js','./cocos2d/core/scenes/CCSGScene.js','./cocos2d/core/layers/CCLayer.js',],'Sprite': [// ...'./cocos2d/core/sprites/CCSGSprite.js',],'Label': ['./cocos2d/core/label/CCSGLabel.js','./cocos2d/core/label/CCSGLabelCanvasRenderCmd.js','./cocos2d/core/label/CCSGLabelWebGLRenderCmd.js',],// ... };

可以看到這里列出了所有會(huì)被打包到引擎中的模塊,而我們需要的 cc.Menu 并不在其中,因此只要把需要的模塊,加入即可,當(dāng)然這里必須注意加入文件的順序的先后,不然還是會(huì)報(bào)錯(cuò)的,其實(shí)可以參考 cocos2d-js 中的模塊導(dǎo)入順序,例如 cocos2d-x v3.10 引擎中的文件 : cocos2d-x-3.10/web/moduleConfig.json 參考上面的文件,添加模塊 cc.Menu 和它需要依賴(lài)的 cc.LabelTTF 等模塊 :

// ... 'Label': [// ...'./cocos2d/core/labelttf/LabelTTFPropertyDefine.js','./cocos2d/core/labelttf/CCLabelTTF.js','./cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js','./cocos2d/core/labelttf/CCLabelTTFWebGLRenderCmd.js' ], 'Menu' : ['./cocos2d/menus/CCMenu.js','./cocos2d/menus/CCMenuItem.js' ], // ...

然后使用 gulp 打包引擎 :

cd CocosCreator.app/Contents/Resources/engine gulp build

刷新工程后,就可以在 CCC 中使用 cc.Menu 了 :

// helloworld.js cc.Class({extends: cc.Component,onLoad: function () {cc.MenuItemFont.setFontSize(20);cc.MenuItemFont.setFontName("Verdana");var menuItem1 = new cc.MenuItemFont("Item1", this.item1Callback, this);var menuItem2 = new cc.MenuItemFont("Item2", this.item2Callback, this);var menuItem3 = new cc.MenuItemFont("Item3", this.item3Callback, this);var menu = cc.Menu.create(menuItem1, menuItem2, menuItem3);this.node._sgNode.addChild(menu);},item1Callback: function() {cc.log("item1Callback");},item2Callback: function() {cc.log("item2Callback");},item3Callback: function() {cc.log("item3Callback");} });

這里為了測(cè)試方便,使用了 hack 的方式將 ccMenu 添加到了場(chǎng)景中,我們當(dāng)然也可以像 cc.DrawNode 一樣,為其設(shè)計(jì)對(duì)應(yīng)組件,來(lái)迎合 CCC 的工作方式。

看到這里,其實(shí)我們就可以了解到,過(guò)去的 cocos 里的那些模塊,并沒(méi)有被廢棄,它們還是在那里,只是官方并沒(méi)有將其集成到 CCC 中,或是因?yàn)闀r(shí)間不夠,或是因?yàn)檎J(rèn)為沒(méi)有必要。

但是不管怎樣,個(gè)人的理解是,只要 CCC 提拱了一個(gè)完善的框架,那么即使部分模塊的缺失,也是完全可以通過(guò)自己來(lái)解決彌補(bǔ)的,畢竟這就是開(kāi)源的好處,放著好好的源碼不看,這不是暴殘?zhí)煳飭?..

(作者還計(jì)劃有生命周期、常見(jiàn)設(shè)計(jì)模式、最佳實(shí)踐、編輯器擴(kuò)展、Gizmo、Native等多個(gè)章節(jié)。期待SuperSuRaccoon繼續(xù)完成這系列教程!)

總結(jié)

以上是生活随笔為你收集整理的从此之后,Creator 再无秘密的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。