麒麟子慣用框架分享(建議收藏)
麒麟子在開發(fā)中搞出來的框架,都是遵守“大道至簡,實用至上”這兩個基本原則。
接觸一個引擎的第一件事,就是搞出一個實用的框架,方便在此基礎(chǔ)上做開發(fā)。
由于目前的引擎已經(jīng)是對象+組件模式,所以在場景對象管理上,不需要花太多功夫了。我們主要集中在界面管理這塊。
既然我們的框架想要滿足日常開發(fā),就不得不滿足星辰大海般的需求。從客戶端的角度,我們可以把游戲分為三類。
1.1、純界面玩法
像一些SLG、卡牌、象棋等可以視作純界面玩法。(也有某些大作要求3D表現(xiàn)效果的,我們不作討論),比如下面的這類游戲。

1.2、某些純界面&戰(zhàn)場場景

1.3、從頭到尾都是3D場景

1.4、小結(jié)
仔細(xì)分析以后我們可以發(fā)現(xiàn),假如我們的框架始終支持 2D/3D場景 +?界面?這樣的能力。就可以了。?
?
單場景+Prefab 和?多場景從 Cocos 2d-x 提供了 replaceScene 函數(shù)開始,就一直有人在爭論這個話題。只要引擎提供了“場景”這個定義的,都會遇上決策問題。
麒麟子看得很明白,所謂的引擎場景管理,就是給了你一次無腦銷毀所有結(jié)點的機會。
如果你是在兩個截然不同的邏輯之間切換,那其實是可以使用引擎的場景切換功能的。?如果邏輯相差不大,我建議依然采用單場景方式。
而麒麟子更推薦的是單場景+Prefab方式,這樣會迫使你自己更注重場景節(jié)點和資源的管理。
3.1、程序啟動入口
程序啟動入口包含兩個部分。
3.1.1、最小場景
最小場景如果不出意外,我們只需要一個Canvas節(jié)點,一個MainCamera節(jié)點,一個MainLight節(jié)點就好了。
3.1.2、App.ts
麒麟子喜歡以 App.ts 作為程序入口,將這個App.ts掛在Canvas節(jié)點上即可。App.ts的內(nèi)容并不多,如下所示
import { _decorator, Component, Node } from 'cc';import { UIMgr, UILayer } from './UIMgr';import { HUD } from './HUD';const { ccclass, property } = _decorator;@ccclass('AppTs')export class AppTs extends Component {start () {UIMgr.inst.setup(UILayer.NUM);UIMgr.inst.showUI(HUD);}}
我們可以清晰地看到,在這里,麒麟子只啟動了 UIMgr,如果還有其他游戲管理器需要一開始就初始化,那么把它們放在這里就好了。?
3.2、界面管理器
界面管理器至少要包含幾個功能
動態(tài)加載和銷毀界面
界面層級管理
界面事件自動管理機制
界面與游戲業(yè)務(wù)邏輯通信機制
上面說的這些,框架里都自帶了。
很多小伙伴一定還在糾結(jié)是用 fitWidth 還是 fitHeight 吧。
如果使用 fitWidth 遇上更細(xì)長的設(shè)備,界面上面部分可能被裁剪。
如果使用 fitHeight 遇上更短的設(shè)備,界面左右部分可能被裁剪。
其實我們想要的只有一句話:任何時候,都不要裁剪。
基于這個目標(biāo),我們制定出的策略就是。
在比設(shè)計分辨率更細(xì)長的設(shè)備上,我們使用 fitHeight,這樣一來,他長由他長,我們只需要保證背景左右能夠填充就行。
在比設(shè)計分辨率更短的設(shè)備上,我們使用 fitWidth這樣一來,他高由他高,我們只需要保證背景上下能夠填充就行。上面的適配機制,已經(jīng)被麒麟子寫成了一個函數(shù)。
public resize() {????//根據(jù)屏幕大小決定適配策略let dr = view.getDesignResolutionSize();var s = cc.view.getFrameSize();var rw = s.width;var rh = s.height;var finalW = rw;var finalH = rh;if ((rw / rh) > (dr.width / dr.height)) {????????//!#zh:?是否優(yōu)先將設(shè)計分辨率高度撐滿視圖高度。????????//cvs.fitHeight?=?true;????????//如果更長,則用定高finalH = dr.height;finalW = finalH * rw / rh;}else {????????/*!#zh:?是否優(yōu)先將設(shè)計分辨率寬度撐滿視圖寬度。*/????????//cvs.fitWidth?=?true;????????//如果更短,則用定寬finalW = dr.width;finalH = rh / rw * finalW;}view.setDesignResolutionSize(finalW, finalH, ResolutionPolicy.UNKNOWN);let cvs = find('Canvas').getComponent(UITransformComponent);cvs.node.width = finalW;cvs.node.height = finalH;}
在設(shè)置面板里面,fitWidth和fitHeight都得去掉,一個都不要勾,否則可能出現(xiàn)設(shè)置失效。
麒麟子在調(diào)用 view.setDesignResolutionSize 函數(shù)的時候,最后一個參數(shù)傳的是ResolutionPolicy.UNKNOWN。
這樣一來,這個函數(shù)是可以重復(fù)調(diào)用且生效的。當(dāng)我們處于微信瀏覽器的時候,橫豎屏旋轉(zhuǎn)會導(dǎo)致寬高比不一致,這就需要再次調(diào)用這個函數(shù)來重新調(diào)整布局。
?
麒麟子這里沒有MVC,也沒有MVVM,只有以下幾個套路
數(shù)據(jù)、數(shù)據(jù)更新方法由邏輯管理器提供 數(shù)據(jù)變更,想讓界面產(chǎn)生改變,則通過事件傳遞 界面可以直接調(diào)用邏輯管理器 兩個界面之間,只能通過事件傳遞(需要兩個界面聯(lián)動的情況非常少,一般情況下界面之間的邏輯都是互不干擾的)
也就是說,邏輯管理器不知道界面的存在,但界面是知道邏輯管理器的存在的。
我舉一個關(guān)于個人信息的例子。在這個例子中,我們會涉及到三個文件 MyInfoMgr.ts(用戶信息邏輯管理器 M) 、UIMyInfoController.ts(用戶信息界面控制器 C) 、MyInfo.prefab(用戶信息界面布局 V)。
如果非要用MVC來對應(yīng)的話,就按我后面標(biāo)記的字母來對應(yīng)吧。
當(dāng)用戶點擊個人按鈕時,UIMgr會實例化UIMyInfoController類,UIMyInfoController類會加載MyInfo.prefab。
當(dāng)加載成功后,UIMyInfoController會有一個onCreated回調(diào),我們可以在回調(diào)里初始化我們的顯示信息。
UIMyInfoController需要監(jiān)聽用戶信息改變相關(guān)的事件,當(dāng)收到事件的時候,需要對應(yīng)地做顯示更新
MyInfoMgr持有用戶數(shù)據(jù)并提供訪問接口以及數(shù)據(jù)修改接口,當(dāng)數(shù)據(jù)產(chǎn)生修改時,會拋出修改事件。它不關(guān)心這個事件是否有人要用。無腦拋出就行。
與其說是框架,不如說是麒麟子的慣用套路。這個套路沒有出色的地方,也不滿足很多學(xué)術(shù)性的依賴解耦標(biāo)準(zhǔn)。但這個套路陪著我走過了大大小小很多項目。
如果要給它下一個定義的話,我覺得就是兩個詞:“簡單、實用”。
哦對了,只能用Cocos Creator 3D 1.1.1打開。
源碼地址:
https://gitee.com/qilinzi/creator3ddemos
