tft每日頭條

 > 遊戲

 > 大天使之劍h5角色技能

大天使之劍h5角色技能

遊戲 更新时间:2024-07-03 07:21:04

想要了解更多的遊戲資訊 一定要關注遊戲陀螺!

導語:

有料,實例分析壓縮優化代碼方案。

随着渠道平台的發展不斷發展及演化,我們的産品往往要登陸各種平台,而微信小遊戲就是這些平台的其中之一。

微信小遊戲是微信小程序的一個類目,它即點即玩,無需下載安裝,體驗輕便,可以和微信内的好友一起玩,比如PK,圍觀等。

但想讓自己的遊戲登陸微信小遊戲,往往會有一些方面的限制。以下是由三七互娛旗下研發公司極光網絡客戶端主程陳策在上周舉辦的首期“極光會客廳”活動上的技術幹貨分享,以《大天使之劍H5》這一項目登陸微信小遊戲受到的主要限制和解決辦法進行實例分析。

大天使之劍h5角色技能(大天使之劍H5主程分享)1

《大天使之劍H5》受到微信小遊戲的主要限制

1.所有分包大小不得超過8M:分包指的是在微信開發工具裡上傳的所有資源,包括JS代碼和資源,一共不得大于8M;

2.單個包的大小不得大于4M:上傳的文件裡,不能有大于4M的文件;

3.JS必須放在分包裡才可以運行,加載進來的JS文件隻會被當成文本:加載進的JS文本,無法轉成可執行腳本

《大天使之劍H5》在登陸微信小遊戲前,整個項目大小約有400多M,光JS代碼部分就有大約10M。除邏輯代碼的其它資源(圖片、音效、配置等),可以在遊戲運行時進行加載,不用在開發工具裡上傳,但約10M的JS代碼部分必須全部上傳。因此,《大天使之劍H5》想登陸微信小遊戲,必須縮小JS代碼的大小。

現有壓縮工具UglifyJS部分功能簡介

LayaBox引擎裡将項目的AS3部分生成JS時會進行一定的優化,這個功能應該是基于UglifyJS來實現的。其優化内容主要有:

1.去掉代碼中無效的空白字符

2.去掉代碼中的注釋

如圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)2

3.把方法中局部變量名縮短

如圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)3

4.代碼格式優化 (把代碼改為更省字符的寫法)

如圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)4

5.壓縮屬性名 (默認不開啟)

大天使之劍h5角色技能(大天使之劍H5主程分享)5

我們先來看看這個例子,這個是一個類,在工具默認不開啟壓縮屬性名稱時,工具就隻會壓例子裡橙色的兩處X和Y,因為這個是參數,也就是剛才說的方法裡定義的變量,this.x,this.y這都是不壓的,因為這個是屬性名。如果類名Point,方法名setTo,屬性名X,Y壓了,那其他使用的地方就要根着一起改,如果代碼裡有用到反射來調用的,那就調用不到了。所以壓縮這些名稱是有風險的,這也就是工具默認不壓的原因。那這個功能不就廢了?不會,工具還提供了很多參數讓你可以設置不壓縮的名稱的列表,還允許你定義壓縮的名稱的正則表達式等等,其實還是可以使用的,隻是還是要先整出一份針對自己項目的名稱數據出來,整理出來的不壓縮名稱集要和代碼同步進行維護,這樣難度會比較大,所以《大天使之劍H5》項目并沒有使用這個功能。

小結:

《大天使之劍H5》項目現有的AS3代碼代碼在Layabox生成JS代碼時,已經默認進行了上述前四點優化:

  • 去掉代碼中的無效的空白字符
  • 去掉代碼中的注釋
  • 方法中的局部變量名縮短
  • 代碼格式優化

但生成的JS代碼有10M左右,還沒有達到微信小遊戲的要求,因此,為了縮小代碼量,我們需要對我們的AS3代碼再做一些優化,從而減少代碼量。

減少程序代碼

縮小代碼量,最直接的方式就是減少代碼裡的字符,這部分所作的優化,是在我們項目的AS3代碼部分所做的優化,這些優化包括以下幾點:

1、将界面布局的數據改為從外部加載

Layabox的UI編輯器編輯後,會生成對應的UI類文件,其内容如圖:

大天使之劍h5角色技能(大天使之劍H5主程分享)6

這裡面主要内容是UI的布局數據,不用涉及到邏輯,可提取出來。做為文本文件保存,在其對應的界面初始化時再加載,在Layabox中,我們可以通過修改UI模式來做調整:

大天使之劍h5角色技能(大天使之劍H5主程分享)7

我們可以随意創建一個UI來做測試,如圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)8

我們可以看到,新建一個TestPageUI界面,使用内嵌模式生成的TestPageUI.as文件共有3283字節,而使用分離模式,生成的文件隻有579字節。圖中右邊綠色部分表示的是減掉的部分代碼,為我們縮小約80%左右的UI布局相關代碼。

大天使之劍h5角色技能(大天使之劍H5主程分享)9

而在《大天使之劍H5》中,UI布局文件目前有931個,使用這種方式幫我們減少了1.8M的代碼。

2、将類裡不使用的導入删除

我們在開發時,手誤import進入的一些項目并未使用到的類,需要将這些import删除。

如:import Sprite3D 類,2D遊戲用不上3D相關的東西,無需導入

3、将方法裡的this用局部變量代替

當我們的AS3代碼轉成JS後,類中的屬性名在方法中的訪問形式,是會在其前面加上this. 這裡的this我們是否能減少呢?如下圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)10

上面的方法裡有若幹個this。如果把this用一個局部分變量來代替,那就是下面的方法這樣。這裡的局部變量用的是一個字符的變量,因為最後我們項目會用UglifyJS來壓,所有方法内定義的變量,隻要不超過54個,都會是單字符的變量。我們看優化前,一共是有四個this,他們占用16個字符。優化後,四個this變成了四個n,是4個字符,還多出一個賦值語句,這個語句包括中間的空格,包手後邊的分号,一共是11個字符,加上四個n就是15個字符,比優化前少了一個字符。如果這個方法裡我再加一個this,那優化前的代碼,就要增加4個字符,而優化後的代碼隻需要增加1個字符,所以方法裡的this越多,能減少的大小也越多。因此:

大天使之劍h5角色技能(大天使之劍H5主程分享)11

總結來說就是隻要方法裡的this關鍵字多于3個,就能省字符數量。而且this越多,省得也就越多。我在編譯好的JS代碼裡搜索,一共是有近18号個this,這個就可以省很多了。但這個優化要注意,每個function都是一個作用域,每個作用域裡的this指代都是不一樣的,所以每個不同的作用域裡的this要分别進行計算,也就是說,方法裡如果有一個函數,那在計算方法裡的this數量時,不應該計算函數裡出現的this。第二個,是有一些方法,已經寫了内部的變量賦值是this的,那就可以利用這個已經存在的變量,可以進一步減少字符。這個優化最終省了0.3M。這個優化優化的不僅僅是代碼的大小,因為在JS裡,局部變量的調用效率是比this要高的,所以這還可以加快遊戲的運行效率。

4、壓縮包名、類名、方法名、屬性名

這一步做的事,是把UglifyJS默認不壓的名稱,我們用我們的方式把他給壓了

① 相同的名稱壓為相同的短名稱,把代碼裡出現的相同的名稱,壓為相同的短名稱

② obj.abc 與 obj["abc"] 區别處理:

默認壓縮規則:obj.abc 寫法的屬性名會被壓縮,obj[“abc”] 寫法的字符串部分不會被壓縮。

想到這種方式,主要是因為UglifyJS也考慮到有些屬性名壓縮後,可能會引起某些屬性訪問不到,UglifyJS的做法是提供個不壓的屬性名的配置列表,但是這僅僅是個配置列表,我們通過這個列表無法定位到代碼裡有用到這些屬性名的地方,有一定的局限性,因此,通過obj.abc 與 obj["abc"] 區别處理,我們可以在寫代碼的時候就用不同的寫法告訴編譯器,這裡的屬性名是否要壓。

有人會有疑問,用obj[“abc”]的寫法,會比obj.abc的寫法多了三個字符。不用擔心,因為在最後用UglifyJS壓縮的時候,會将[]語法轉成.語法的。

③ 自定義标簽 /*[ZIP-JSON]*/

為了不破壞程序員的編程習慣,我們在不得不用字符串的形式去

訪問屬性時,想到了下面的解決方案:在字符串前加上一個/*[ZIP-JSON]*/

如:

大天使之劍h5角色技能(大天使之劍H5主程分享)12

我們常用的緩動類的用法中,上圖的”x”和”y”是屬性名,我們默認情況下字符串是不會被壓縮的。此時我們可以在代碼中加上/*[ZIP-JSON]*/标簽,如:

大天使之劍h5角色技能(大天使之劍H5主程分享)13

這樣,”x””y”就會被壓縮成對應的名字了。

通過這些處理,我們的代碼的寫法就會有以下幾種形式:

大天使之劍h5角色技能(大天使之劍H5主程分享)14

形式1:label 這個屬性名,并不會被壓縮,訪問時也用它原名訪問

形式2:label這個屬性名在定義時就被壓縮了,可以通過也會被壓縮的.語法去訪問

形式3:label這個屬性名在定義和訪問時都有被壓縮

當然,/*[ZIP-JSON]*/做為注釋塊,在最後AS3被轉成JS時,UglifyJS會幫我們把注釋塊給清除掉的,不用擔心加了注釋塊反而代碼會大的問題。

④ 特别處理

諸如 hasOwnProperty、propertyIsEnumerable 等方法,以及Layabox 裡的 __JS__ 方法

方法裡傳入的字符串,其實是屬性名稱。因為默認屬性名稱是會被壓縮的,而字符串是不會被壓縮的,所以對這些方法中名字,我們默認進行壓縮。但要壓縮成什麼樣的名字呢?

大天使之劍h5角色技能(大天使之劍H5主程分享)15

上面我們講的,是哪些名稱要壓,壓的時候要注意的一些點,那最終這些名稱,要壓成怎麼樣呢?當然是壓到越小越好,那最小是多少呢?一個字符是最好的。我們先看看要做名稱,受哪些限制。名稱是可以由字母組成的,字母是區分大小寫的,還可以使用數字,還有下劃線,還有一個比較不常用的$符号,要注意的是,名稱的首字符不能是數字。

如果我們把名稱全用單個字符,可以有多少個名稱呢?26個小寫字母,26個大寫字母,10個數字不有用,加兩個符号,就是54個。那雙字符的名稱呢,就有3456個,三個字符就是22萬個。當然這裡能用的還會少幾個,為什麼呢?因為比如像as,is,if,for這樣的名稱,也是兩個字符三個字符,但他們是關鍵字,名稱不能和關鍵字重名,不過這樣的關鍵字也不多,不多于10個。三個字符可以有22萬個名稱,那是否夠我們使用了呢?

大天使之劍h5角色技能(大天使之劍H5主程分享)16

上圖是《大天使之劍H5》中所用到名稱字數的分布圖,一共有4萬個名稱,那兩個字符的3千多個肯定是不夠的,三個字符的22萬個就完全可以滿足了。而且我們看看這些名稱的長度分别是多少,可以從表裡看到,95%以上的名稱是大于三個字符的,那可以優化的空間就比較大了。最終我們項目把名稱都壓縮完後,一共減少了1.9M。在壓縮名稱這裡,大部分工作都是用編輯工具去完成的,有一部分是要修改源代碼的,也寫了一個工具去處理,盡量做到用工具去完成,不然要手動去修改,工作量會變得超大。

上述的五點對《大天使之劍H5》優化過後,結果如圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)17

《大天使之劍H5》的代碼由約10M減小到約5.1M的大小

⑤ 一些還未在《大天使之劍H5》中做的可取優化

  • 靜态常量編譯為JS後是把值寫在使用的地方,這不一定是最優的
  • 方法裡使用的屬性賦值給局部變量再使用
  • 使用(param)=>{}代替function(param){}
  • 某類隻有一個子類時可減少繼承鍊
  • 包結構可以減化

四.使用分包

在上述的優化後,《大天使之劍H5》的主代碼還有5.1M,任然需要對這5.1M進行拆分,這5.1M中,有遊戲引擎的部分占了0.7M,其他小文件占了0.2M,剩餘的主程序還有4.2M,剩餘的4.2M可以通過分包處理。怎樣分包我們可以在騰訊和layabox的官網上找到詳細的教程 。

關于在layabox下是如何分包的,在這裡簡單說一下:

大天使之劍h5角色技能(大天使之劍H5主程分享)18

在項目的根目錄下,創建一個module.def文件,這是一個文本文件,裡邊的内容如下,就可以在編譯後,生成主文件的JS和模塊.js兩個文件。如果要分為多個模塊的,就把這個結構寫多個,都定義好模塊名稱和模塊對應的代碼所在的文件夾就可以了。

看起來是不是很簡單?但我們随意的指定一個文件夾下的代碼被編譯為一個模塊獨立出去後,在運行時,就會出錯上圖紅色部分的一個報錯。

出現這個報錯的原因是主文件會先運行,主文件裡引用了模塊裡的XXX,而運行到這裡的時候,模塊還沒有被加載,所以xxx沒有被定義,所以報錯了。

所以,要做好分模塊前,就需要對項目進行解偶。要解偶的話,那就得知道,我們分到模塊裡的是什麼功能,這個功能裡如果需要和主程序進行交互,就需要設計相應的中轉機制來進行解偶。

如果項目是新項目,我們可以在一開始設計遊戲的時候就做好這部分内容,在功能進行開發中,會知道這個功能是要分出去的模塊,要以怎麼樣的開發規則進行開發,就可以做到解偶進而做到分模塊。

但我們的遊戲已經上線快一年了,如果現在才加入這樣的機制相當于我們要對需要放到模塊裡的功能進行重構,這樣做工作量大,而且功能還要重新測試,開發周期開,還容易出BUG。後來我想了一個不需要解偶也可能分模塊的辦法。

大天使之劍h5角色技能(大天使之劍H5主程分享)19

我在說我們辦法前,我要說明一點,我這個辦法隻是為了解決在小遊戲裡做到分包小于4M而做的,與分模塊的設計思路是不太一樣的。分模塊的目的是什麼呢?是把還沒有使用到的功能放到模塊中去,需要使用到的時候,再去加載對應的模塊。而我的做法,是需要在進遊戲前,需要把所有模塊都加載進來,無論模塊的功能是否需要,也不管模塊裡到底是什麼功能。

為了說清楚這點,我們先來看看JS的類。JS的類定義在書寫的時候,是否有先後順序?看看這段代碼,這裡定義了一個父類,然後再定義了一個子類。這裡我們是否能先寫定義一個子類,再寫定義一個父類嗎?大家注意下子類的定義裡,是需要将父類的定義傳入的,如果先寫子類的定義,那傳入的父類定義就是一個undefined,裡邊在調到到父類定義裡的屬性時,就會報錯。所以父類必須要寫在子類前邊。換成分模塊的情況下是怎麼樣呢?

假設我們現在有兩個文件,先被加載的叫模塊A,後被加載的叫模塊B。模塊A裡有一個子類的定義,在模塊B裡有其他類的定義,也包括這個模塊A裡的子類的父類的定義。在模塊A被加載完成後,運行到子類的定義時,就調用到了他的父類,因為模塊B還未加載,所以必然報錯了。這裡我們要怎麼避免報錯呢?很簡單,把父類的定義,也放到模塊A裡,那就不會報錯了。如果父類還有父類,而且也在模塊B裡的,那記得也要把他的父類也拿到模塊A裡。

具體我們是怎麼操作把父類也放到模塊A裡的呢?我們隻需要在調用Laya的編譯器前,把父類的as文件考到模塊A的文件夾裡就可以了。父類裡的包名什麼的,都不需要做修改。要知道包名在AS裡雖然是和文件存放的路徑相匹配的,但在用laya編譯時,是不檢測包名是否和路徑匹配的,最終生成到JS裡的,是文件裡寫的包名,路徑隻做為是放到哪個模塊的依據。

大天使之劍h5角色技能(大天使之劍H5主程分享)20

剛才我們講的是父類是在另一個模塊的情況下引起的報錯。除了這個,還有沒有其他情況呢?有的,比如說我們在剛才的模塊A裡的類,在未解偶的邏輯裡,是肯定有調用到模塊B的類。不過在初始化時,應該不會運行到業務邏輯裡,那為什麼會報錯呢?

我們來看看模塊A裡的代碼。模塊A裡的頭幾行一般是長這個樣子的,第二行,是将Laya引擎裡的一些公共方法定義了短名稱的變量,方便在邏輯裡調用。第三行開始,就是把這個模塊裡引用到的類,都用類的名稱做變量名賦值,這樣就方便在使用的時候,不需要寫包括包名的類名稱。也就是我們直接寫在AS裡的代碼,不用做太多修改就可以在變成可運行的JS。

要注意到,這幾行代碼,是在這個JS文件初始化的時候就會被運行的。注意看第四行,我們有一個類,假設這個類叫ClassName,這個類是定義在模塊B裡的,那這句賦值語句就會因為模塊B還未加載而找不到ClassName的定義,然後報錯。而且這個類之所以出現在這裡,就是因為在該模塊的某個類裡使用了它。

這裡我們就明白了,寫在類的方法裡的代碼,在初始化的時候是不會被運行的,所以寫了模塊B裡定義的類也不會在初始化時報錯,被導入的類會被寫到模塊的最開頭,會在初始化時運行到就會報錯。那我們這麼處理,所有模塊A裡的類,如果import的類是模塊B的類,那就把這個import删除掉。并且把所有使用這個類的地方,都寫成用這個函數調用的字符串的包括包名的類名。

大天使之劍h5角色技能(大天使之劍H5主程分享)21

好像這樣改,需要改的地方會比較多,而且生成的代碼裡,也會有多處長名稱,我改成了這樣,在類裡加一個靜态的變量,讓他等于這個函數,那代碼裡就不用修改,使用到這個類名的地方,其實調用的是這個定義的靜态變量。而且編譯為JS後,靜态變量的定義會變成get函數來得到這個值也就是在使用的地方才會調用,而不是初始化的時候。這樣就解決了模塊A的代碼裡調用到模塊B的類的引起在初始化的時候報錯的問題。

大天使之劍h5角色技能(大天使之劍H5主程分享)22

做好剛才的兩個地方就完成了嗎?我們再回想一下兩個情況,都是模塊A裡的類,如果引用了模塊B裡的類,那就想辦法把他的引用去掉,讓他在首次運行時才調用。也就是說,在編譯為JS的時間,模塊A裡的類是被當成沒有引用模塊B裡的那個類了,那如果模塊B裡的那個類,假設叫SimgleClass,隻有唯一的一個引用就是模塊A裡的類引用了,現在把模塊A裡的引用去掉了,那SimgleClass就沒有類引用到它了,也就是編譯的時候,會把這個類不編譯到JS裡去。那運行的時候就會因為找不到定義而報錯。所以要在SimageClass裡加上強制編譯的标簽,這個是由LayaBox提供的标簽,當有這個标簽時,這個類就算沒有引用,也會被編譯到JS裡去。

最終的結果,如圖所示:

大天使之劍h5角色技能(大天使之劍H5主程分享)23

這4.2M的主程序文件,就被拆分為了一個1.2M和一個3M,小的那個和引擎代碼還有其他一堆小文件一起打包成一個包,共2.1M,3M的那個文件就一個包。在程序運行的時候,會在進入遊戲的時候,先加載2.1M的包,完成後會立即加載3M的包。兩個包都加載完成後,才會進入遊戲。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关遊戲资讯推荐

热门遊戲资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved