文章按照作者調研和開發順序初步介紹和了解了微信小遊戲和白鹭引擎,并産出了基于白鹭引擎的應用初始化程式egret-wechat-start。 以下是正文——
如何開發和了解微信小遊戲,先從官方文檔和官方demo入手。 提供一個連結https://developers.weixin.qq.com/minigame/dev/,可以快速浏覽一下官方文檔再繼續看下面的内容。 這裡對微信文檔做個簡單的了解總結,小遊戲和小程式很多地方類似,都是提供了同一套微信Api,比如擷取使用者資訊、toast等等,隻是有部分提供的api不同。 小遊戲對canvas做了封裝,通過 <code><code>wx.createCanvas() 建立畫布,</code></code><code>getContext擷取對象後,剩下的就是對原生canvas接口的操作了。 了解到這一點之後,我們就會發現小遊戲僅僅是封裝了下建立畫布的接口,剩下的就是使用者需要在畫布裡用原生canvas繪制了,并沒有提供其他友善開發的功能。到此我們再看看微信開發者工具建立小遊戲項目時,初始化的一個飛機遊戲的demo。 </code>

<code>是如上圖的一個很簡單的遊戲,說下這個遊戲的大緻實作邏輯:</code>
1. 繪制遊戲區域,背景圖檔
2. 建立敵機對象,使用者飛機對象,子彈對象
3. 控制3種對象載入畫布和位置改變,控制背景圖檔移動,添加音效
4. 判斷子彈碰撞,機身碰撞,并且生成對應結果(敵機消失,遊戲結束)
遊戲中和使用者有互動操作有拖動飛機和彈框中的按鈕,總體是一個很簡單的小遊戲,實作過程也并不複雜。 官方demo中最核心的動畫内容就在loop方法裡,使用的是幀動畫( requestAnimationFrame )來實作界面動畫。 針對遊戲實作動畫效果主要有兩種方式,一種就是requestAnimationFrame幀動畫,一種是用定時器實作。 幀動畫和裝置的處理速度有關系,預設1秒60幀,但是在手機裝置裡即便很簡單的動畫,性能差點的裝置可能幀率都隻有20-30左右。 因為幀動畫每秒就要調用n次,也許并不需要那麼高頻率的函數調用,而定時器總的來說對時間的把控和函數調用次數更準确。 比如這個飛機遊戲裡如果有血條的概念,血條的加減其實可以用單獨的定時器來控制。 一個遊戲裡可以兩種方式都使用,根據應用場景選擇更合理的方式。
現在根據一個新的需求來做一個遊戲,再來了解小遊戲的開發。 現在需求實作一個回合制遊戲,這個遊戲也有很多頁面,首頁就包含很多按鈕和可能出現的彈窗,也有各種清單頁,還有最關鍵的戰鬥頁面。 在做實作需求之前,需要提供一些公共的基礎子產品:資源預加載,接口攔截器,簡易路由等等。 跳過這些階段,如果我們拿到ui設計,開始做首頁了,首頁有很多按鈕,我們需要給A按鈕添加綁定事件,那我們需要給canvas畫布綁定一個點選事件,點選觸發以後我們擷取到目前使用者點選位置,并取出A按鈕的位置寬高并計算出範圍,進行判斷是否點選位置在範圍内,最後再觸發綁定的方法。 好像有點麻煩,但是還能實作,繼續做下去。 後來需要在首頁做一個彈框,這個時候,給彈框的B按鈕綁定點選事件,又需要通過同樣的方法判斷是否點選到B按鈕。 這個時候彈框的B按鈕剛好和A按鈕重疊都在一個點選範圍内,那按鈕A和B的回調都會被執行。 代碼如下:
一個彈窗上面的按鈕點選,反而把彈框下面的按鈕也點選到了,這不符合預期,那要解決這個問題,我們還需要一個層級管理器,根據層級判斷誰應該觸發,誰不應該觸發。 目前就事件處理我們需要實作兩個基礎功能,事件監聽池和元素對象層級管理器,因為事件隻能綁定在canvas上,canvas事件觸發以後,需要一個事件監聽池來周遊監聽池裡的元素對象并判斷誰被觸發了(監聽池也會随時增減監聽對象),監聽池擷取的依然是一個對象集,層級管理器判斷出對象集裡最上層的元素進行觸發。 想想功能好像越來越複雜了。 目前還沒考慮完善,不僅僅是事件處理問題,還可能會有其它大大小小的問題。 用canvas原生開發,工作量可能會非常大。 是以這樣看來,自己把這些實作了是不科學的,需要使用三方引擎開發才行。 因為兩年前用過白鹭引擎,是以就事件監聽和層級管理這個事情,我知道白鹭引擎已經實作了,除開事件,圖形繪制,動畫等等印象中白鹭都提供了,如果用引擎開發小遊戲實作成本被大大降低。
白鹭引擎功能很強大并且豐富。 這裡我先介紹一下我主要使用的工具。
Egret Engine2D
Texture Merger
Egret 擴充庫
Egret Wing
開發中主要的核心api
Texture Merger 可将零散紋理拼合為整圖,同時也可以解析SWF、GIF動畫,制作Egret位圖文本,導出可供Egret使用的配置檔案。 我主要使用其中的精靈圖功能,把圖檔集合到一張圖上,并且會同時導出一個json的精靈圖的在圖檔中的位置等配置資訊
擴充庫在核心引擎功能之上提供了更進階的api,擴充庫在引擎配置檔案裡配置好以後,會直接把方法和對象載入到egret全局對象中,目前我主要使用的擴充庫有:
RES: 資源管理庫
EUI: EUI是一套基于Egret核心顯示清單的UI擴充庫,它封裝了大量的常用UI元件,能夠滿足大部分的互動界面需求,即使更加複雜的元件需求,您也可以基于EUI已有元件進行組合或擴充,進而快速實作需求。
Game:這個庫好像沒有什麼專門的定義,我主要使用了:ScrollView 滾動視圖。 來處理需要滾動的頁面
Tween: 緩動動畫庫,類似于GreenSock庫
白鹭開發的代碼編輯器,像其他編輯器一樣,推薦使用它。
當然還需要安裝一個egret launcher來管理引擎、工具和項目打包,小遊戲就需要打包之後才能在微信開發者工具裡使用
你可以快速浏覽一遍官方教程,以便更好對下文有所了解,http://developer.egret.com/cn/github/egret-docs/Engine2D/getStarted/helloWorld/index.html 。 文章不是教程是以會省略掉那些白鹭官網裡的教程。 現在我們使用egret launcher建立一個初始化項目,初始化後的檔案結構如下圖,我展開了resource和src檔案夾,因為我們需要操作的主要是這兩個檔案夾,resource檔案夾主要是存放靜态資源,我們的代碼都在src裡,白鹭使用的是typescript。
在wing工具裡,我們可以馬上開啟調試,就可以在浏覽器或者它自帶的容器裡預覽效果。 main.ts是啟動檔案,main中首先使用await對resource中定義好的圖檔資源進行了預加載,是以預覽開始後會出現loading效果,loading的繪制是寫在src中LoadingUI.ts,圖檔加載完成以後,main裡直接建立了下圖2的頁面,并且添加了一個按鈕,點選後會出現一個彈窗。 效果如下圖。
至此,初始化demo已經告訴了我們如何繪制圖像和綁定事件了,如下圖,我隻截取了click按鈕的代碼,圖像繪制首先需要建立一個相應的egret或者eui對象,比如eui.Button、egret.TextField、egret.Bitmap等等,然後給對象設定相應屬性,比如label、x y坐标,width, height等。 再使用main的addChild載入到畫布中(下面的this就是main對象,main繼承于eui.UILayer)。 demo中的代碼在載入loading的時候,使用了this.stage.addChild,直接addChild或者使用stage.addChild都可以載入到畫布中。 白鹭封裝的addEventListener方法和原生js的監聽方法是一樣的使用方法。
demo的代碼說到這裡總結一下,我們在main入口對象中可以使用addChild載入一個視圖對象到畫布中,比如文本,按鈕等。 我們也可以在main裡addChild一個視圖容器A,視圖容器A也可以添加文本按鈕等,那我們在視圖容器A中再次addChild視圖容器B,那麼這樣就形成了層級嵌套main->A->B,如果想象成dom元素就是div.main->div.A->div.B的關系,我們用代碼來對比一下:
對應
根據以上代碼的了解和我們要做的需求(實作一個回合制遊戲,這個遊戲也有很多頁面,首頁就包含很多按鈕和可能出現的彈窗,也有各種清單頁,還有最關鍵的戰鬥頁面)。 我在main裡寫一個initElement方法,建立基層容器,代碼如下圖,addChild預設根據先後順序确定上下層關系,先載入的在下層。 首先最下層建立了一個背景層,接着是ScrollView和baseContent,頁面容器會載入到他們之中,如果頁面需要滾動會把頁面視圖對象載入到SV中,不需要滾動會載入到baseContent中,Layer和loading在更上層的位置。
基層容器準備好以後,我們可以建立一個首頁頁面。 我會建立3個檔案:base.ts,Index_ui.ts,Index.ts。 Index繼承Index_ui,Index_ui繼承base。 所有的_ui都會繼承base,base會定義通用方法和屬性。 因為一個頁面到最後可能代碼量會比較大,甚至比較亂,是以才把一個頁面拆分成page和page_ui,_ui裡寫視圖相關代碼,page裡調用_ui的方法、處理請求和編寫邏輯,達到視圖和邏輯分離的效果。 當首頁寫好以後,需要建立一個簡易路由,用路由提供的方法把Index添加到SV容器中。 我把路由直接寫到了main中,changePage就是頁面切換的方法,代碼大緻如下:
通過remove和add視圖容器達到了切換頁面的效果。 下面說說編寫_ui頁面的規則,下面是Index_ui的部分代碼,el_layout提前把頁面元素的布局資訊提前定義并統一管理。 把Index邏輯頁面需要操作的元素引用到$el對象裡友善調用和操作。 把資料資訊統一放在$data中。 建立頁面視圖元素之前,需要把第一個元素的y坐标傳給 $firstEleY 這是為了後面pageContentCenter方法能擷取到準确的頁面内容高度,pageContentCenter要執行在所有頁面元素建立完成之後,pageContentCenter會根據目前頁面的高度再比對目前裝置的高度進行垂直居中。
//背景
let RES_bg = new egret.Bitmap( RES.getRes('indexbg') );
$util.setLayout(RES_bg, this.el_layout['indexbg']);
RES_bg.fillMode = egret.BitmapFillMode.REPEAT;
this.$main.PageBg.addChild(RES_bg);
一個簡易的開發封裝的核心代碼已經搭建好了,而後我們還需要封裝一些其它工具類,如下圖:配置檔案($config)、封裝攔截器($api)、濾鏡($filter)、工具函數($util)、微信api封裝(Wx)。 Platform.ts是白鹭自動生成的檔案,根據它的規則自己寫了一個Wx.ts檔案,由于不同平台的接口形式各有不同,白鹭推薦開發者通過這種方式封裝平台邏輯,以保證整體結構的穩定,白鹭推薦開發者将所有接口封裝為基于 Promise 的異步形式。
和src同級的還有一個texture檔案夾,裡面是TextureMeger使用精靈圖的相關檔案,放在倉庫裡是友善後期管理。
簡易的初始化demo,我已經更新到github上https://github.com/zimv/egret-wechat-start。 egret-resource是源碼,egret-resource_wxgame是白鹭打包後的檔案夾,它在開發者工具裡運作。 egret-resource_wxgame應該在ignore裡忽略,這裡沒有忽略是友善下載下傳源碼的朋友直接在開發者工具裡運作demo。 目前程式使用白鹭引擎版本5.2.5。
demo裡随便寫了幾個頁面,看下效果:
還有踩過很多坑,下面記錄一下:
在公衆号背景把設定裡的服務類設定成遊戲類,輸入appId後會自動打開開發者工具遊戲開發的界面
小遊戲自定義字型微信支援程度差
部分功能和api需要注冊的小程式才能使用,比如轉發功能,目前注冊了一個個人小遊戲用于前期開發
使用wing工具編輯代碼,編譯調試,編譯後的代碼會存放在bin-debug檔案夾裡,我用的mac,項目菜單裡有三個選項編譯、調試和清理。我新增了一個xx檔案,卻在調試的時候一直報錯,檢查浏覽器source裡也沒有新增的檔案,bin-debug也沒有,弄了很久,一直以為是自己代碼寫錯了,最後意識到可能是編譯器有問題,這個時候我點選了清理按鈕,新增的檔案就在bin-debug裡出現了。應該是個bug,要多注意檢查bin-debug裡的檔案是否有更新
RES.getResByUrl是網絡異步加載,需要提前addChild保證層級正常,請求完成再修改對象的texture屬性,也可以通過addChildAt方法指定層級。
TextField 字型size小于10會影響布局,文本是否換行取決于設定的元素高度
webgl模式無法加載網絡url圖檔
scrollView有addChild方法,但是方法裡的代碼是直接抛錯,表示不能用這個接口。它的子元素綁定touchStart move等事件會失效,是以目前又增加裡一個baseContent,根據需求切換父容器
measuredHeight這個測量接口隻會測量最上面元素和最下面元素的實際高度,是以第一個元素如果y值大于0要注意配置$firstEleY
所有圖檔用工具壓縮,會減少上傳代碼的大小和提升資源加載速度
當這一切都準備好以後,剩下的就是體力活啦,當然還有遊戲最重要的核心玩法實作、動畫和互動效果,這些可能是一個遊戲實作難度最大的部分。倉庫位址:https://github.com/zimv/egret-wechat-start 。
有沒有人打賞?沒有的話,那我晚點再來問問。
關注大詩人公衆号,第一時間擷取最新文章。
如果你有購買鋼琴的打算,可以從這裡了解到在售資訊,價格實惠品質保障。
---轉發請标明,并添加原文連結---