作者:ManfredHu 鏈接:http://www.manfredhu.com/2018/03/15/31-laya-game-tips/index.html 聲明:版權所有,轉載請保留本段信息,謝謝大家 LayaBox Web前端最近都在跨界!!現在又伸手到游戲領域了。但是真的那麼好跨界嗎?請讓 ...
作者:ManfredHu
鏈接:http://www.manfredhu.com/2018/03/15/31-laya-game-tips/index.html
聲明:版權所有,轉載請保留本段信息,謝謝大家
Web前端最近都在跨界!!現在又伸手到游戲領域了。但是真的那麼好跨界嗎?請讓我一一道來。
Canvas和WebGL的出現其實讓Web游戲有了實現的可能,但是讓我們用ctx一個個畫,效率還是低了點,所以需要游戲引擎。它幫助我們去動態渲染游戲每一幀的元素。
業界比較著名的幾個H5游戲引擎,有Egret(白鷺),Layabox,Three.js,coco2d-js等等,詳情可以看知乎的回答。
因為我們團隊不是一開始做游戲的,我們是傳統意義上的前端團隊,從web發家的,起初做的是電商類的業務——拍拍。所以這裡我們綜合幾家游戲引擎,選擇了Layabox。
有如下有點吧:
- LayaAir是一個優秀的適用於多端的游戲引擎,配備有豐富的組件,有自己的IDE可以快速構建佈局等,不需要寫類似CSS的代碼
- 支持html的頁面渲染,就是說你可以讓游戲引擎跟web頁面,混用(這在一些類似文本的頁面非常有用)
- 支持2D、3D甚至VR方面的開發。性能也足夠優秀
- 對Web前端普遍的上手難度也較其他引擎框架簡單很多
- 不需要寫重構(CSS)代碼
其實我們團隊之前也是做得H5競猜小游戲,不過是基於DOM的,用CSS3做動畫。但是發現CSS3操作複雜動畫,有很多缺點:
- 複雜動畫支持度非常差
- 頁面元素太多,渲染性能差
- 很多複雜的需求做起來很耗時
- 玩家手機容易發燙(頁面元素多,動畫複雜)
因此,我們經過預研和討論,果斷走出傳統Web的開發模式,擁抱傳統的游戲開發!!當然這裡肯定不是一帆風順的,從Web前端轉向游戲開發,還是有非常多的坑點的。
首先需要擺脫HTML和CSS,你不是在做頁面,你是在做一個游戲!!游戲的邏輯占據了一個游戲80%的工作量,所以你很多時候是在寫JavaScript代碼,這不是問題,其次,你需要擁有面向對象編程的思想。這可能是很多老前端欠缺的,因為JavaScirpt說到底是一門面向函數、面向過程的語言。大家知道模塊化,但是卻還是習慣寫function
而不是ES6的class
。
這裡因為平臺也在轉型向ES6靠近,所以大膽採用了ES6+Babel+Webpack
的模式,甚至於在做Weex、小程式、Web三端融合。即一份代碼,可以在三個平臺跑。扯的有點遠哈,下麵開始正文,我們不說用法,具體是說一些坑點,和優缺點對比。
游戲引擎不適用的地方
游戲引擎這東西在動畫一塊是真心好用,可以高度還原設計師的動畫,可是其沒有網頁的排版佈局,更多的佈局應該是通過x、y、更改pivot、anchor屬性來實現。
CSS可以很快速的通過代碼進行相關佈局(flex、float、position等屬性),網頁那種自上而下的內容排版可以自動適應內容,對文字處理十分便捷。
針對各自的優缺點,從實現的便捷性來說,游戲主場景(動畫極多)的情況下,為了提高用戶的體驗,應該用游戲引擎來寫。
而對一些活動浮層、投註記錄、游戲規則等有大量圖片文本的頁面,應該用傳統的Web網頁來編寫,這樣才是物盡其用的做法。
在這個背景下,游戲開發的前端需要掌握多好幾種技能——簡單的游戲開發的技能、重構部分的構建技能(團隊大前端的趨勢下,去除重構崗位,重構工作由前端接管),可以說工作量翻了一倍。但是在業務側來考慮,因為減少了相關的中間環節,需求迭代可以更快速的落地。
Laya的IDE使用要註意的地方
LayaIDE提供一個組件庫,如list列表,tab按鈕切換等等簡單的Web組件,可以直接拖拽使用而不用自己用代碼再實現一次。
但是IDE自帶的很多組件有坑點,如list組件的selectHandler觸發並不靈敏,數據源重新綁定後會出現點擊無法響應的問題,這個時候要綁定mouseHanlder來代替點擊事件等。
IDE的使用對於不熟悉的人來說上手並不簡單,熟練後可以提高效率。具體可以看官網的介紹。
sceneColor並不起作用
這個屬性是IDE的一個配置屬性,在引用的時候並不會起作用。可以理解為是一個IDE的背景色,可以讓你在用IDE編輯的時候看的更清楚。
如果你需要更換背景色,應該通過繪製一個底部的矩形來實現。
1 | this.graphics.drawRect(0, 0, this.stage.width, this.stage.height, '#404d6f'); //設置背景顏色 |
var和name
var
一般組件view下不管嵌套的層級多深,只要有一個var屬性的命名,都可以用this.xxx
來獲取到這個var屬性得帶組件的引用,並對其進行邏輯操作。
name
而name在特定的組件內name有自己的命名規則,如list下的box,命名為render,可以自動識別該box為list內部渲染節點,設置list的repeat等值,直接簡便的實現某些功能。
再譬如dialog界面,我們設置btn的name為close、yes、no等值,可以直接實現關閉dialog視窗的功能等等。name在這個組件下麵也是唯一的,可以用來區分不同的組件。
top、right對x,y的影響
如果組件設置了top、right等值,在對其進行x,y變化是無效的。
解決方法:IDE通過這些屬性設置好佈局要取消掉,會轉化為對應的x、y值,此時可以操作
圖集圖片過大導致圖片載入失敗
之前按照引擎官方人員的建議設置最大合集圖片為2048乘以2048,後面經過我們的測試發現1024寬高比較適配大部分機型,即圖片最大不能超過1024,否則微信手Q會有圖片load時間過長導致失敗的問題。
這裡可能是部分合併的大圖片下載失敗,也可能是全部下載失敗。然後引擎會單獨去下載每個碎片文件,而伺服器是沒有這些文件的,導致下載全部返回404。應該儘量避免這種情況發生。
顯示區域與點擊區域並不完全相等
用一句話來說就是:你看到的並不一定是真實的。如我要完成收起按鈕,然後隱藏整個浮層。
但是你明明可以看到,綁定的點擊事件卻沒有觸發。
這是因為這個層級的高度或者寬度太小,被遮擋這部分是不會觸發的。但是是可見的
分離代碼和工程
起初是因為不想在LayaIDE下寫代碼,所以分成了兩部分,後面發現這種形式還是非常OK的,因為Laya工作人員不是傳統前端開發,他們的IDE是類似Atom的Electron做的,所以其實運行起來編碼體驗並不是太好。其次是因為IDE會生成圖片(png)和圖集(atlas)文件,這些圖片類的靜態資源,更新頻率還是非常高的。如果你只需要修改代碼,或者只要修改圖片圖集,發佈一次就好了,不需要同時發佈兩種。
這樣的分離,代碼你可以按照你喜歡的方式來寫,比如webpack配置工程,比如文件擺放,該怎麼放怎麼放。再把Laya生成的東西拷貝進來就好了。
設計稿和工程大小
這裡我們設計稿和IDE的寬度高度是完全對應的,所以不存在換算的問題。也不需要類似CSS的做REM相容等等操作。你設定寬度是750,高度會自動拉伸,但是顯示的頁面層級,需要在初始化的時候拉伸一下,不然還是IDE裡面設定的寬高,當然如果你害怕上面提到的點不到,也可以設定一個非常大的值。
Object.assign相容
Object.assign是ECMAScript標準的合併對象屬性的方法,類似有jQuery的extend等等。
如果你拋棄了jQuery和Zepto等懶得寫extend方法,又擁抱了ES6,那你可以像我這樣找polyfill來相容,這裡babel官方有個模塊
也可以自己選擇做相容,在入口開始的時候載入相容文件就好。
抗鋸齒問題
這個問題是在WebGL下(Canvas不會),會出現graphics.drawCircle
繪製的圓環有鋸齒問題。如下圖:
左邊為沒有設置抗鋸齒,右邊設置了抗鋸齒。
1 2 | Laya.Config.isAntialias=true; //開啟抗鋸齒,會消耗一些性能 Laya.init(Browser.clientWidth, Browser.clientHeight, WebGL); |
mask遮罩不支持抗鋸齒
如圖,下邊是沒有優化前的,鋸齒嚴重。上邊那個圖是優化後的,明顯邊框清晰了很多。
這裡之前的思路是矩形頭像和mask遮罩為一個整體在前面,然後內邊框和外邊框層級在後面,但是這樣的話,mask遮罩部分現在laya還不會抗鋸齒,所以這裡對公共頭像組件進行參數擴展,加了zOrder參數。讓邊框蓋在頭像上,就可以達到抗鋸齒的作用。
最後實現的思路如下圖層級所示。
Laya幾種優化的寫法
用Laya自帶的屬性獲取像素比
1 2 3 | //var browserHeight = document.body.scrollHeight * window.devicePixelRatio; var browserHeight = Laya.Browser.height;//會考慮設備像素比,而且會針對特定機型調整補全 ` |
這個不用自己算了,Laya.Broswer
現在可以獲取得到了。簡化了運算過程
用.super()方法繼承父類
Laya.class定義的時候會在原型定義.super方法,直接用就好。兩種用法等價,但是看起來.super更簡單把?
可能有一些例子是通過xxx._super.call(this)
繼承父類的,其實直接xxx.super(this)
就好了。_super
還是看成私有屬性好了。