使用Laya引擎開發微信小遊戲(上)

  使用一個簡單的遊戲開發示例,由淺入深,介紹瞭如何用Laya引擎開發微信小遊戲。
  
  img
  
  作者:馬曉東,騰訊前端高級工程師。
  
  微信小遊戲的推出也快一年時間了,在IEG的遊戲運營活動中,也出現了越來越多的以小遊戲作爲載體運營的活動類型,比如遊戲預約,搶先試完等等,都收到了非常良好的效果。
  
  在支持微信小遊戲的遊戲引擎中,Cocos,Egret,Laya都對小遊戲的開發提供了很多強大的支持。前段時間正好抽空研究了一下這塊的內容,現做一個總結,針對如何使用Laya引擎開發微信小遊戲給大家做一下介紹。因爲時間有限,研究並不深入, 如有高手路過,忘不吝賜教。
  
  做個啥遊戲呢?“絕地求生”很火,我們做個“絕地求死”如何?策劃也很簡單,和絕地求生相反,主角不是跳傘的玩家,而是地面的炮手,大炮要把跳傘的傘兵用大炮一個個都消滅掉。
  
  牛逼的策劃有了,咱們進入正題,看看怎麼實現吧!
  
  1. 如果不用引擎會怎樣?
  
  1.1 Canvas瞭解下
  
  微信小遊戲提供了canvas這個遊戲核心組件。利用Canvas可以在畫布上畫出文字、圖形、圖像等等。 不過講微信小遊戲之前,得先說說H5,在H5時代獲取canvas對象非常簡單,如下圖:
  
  var canvas=document.getElementById("myCanvas");
  
  var ctx=canvas.getContext("2d");
  
  常用的一些API:
  
  ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); //繪製圖片
  
  ctx.fillText(text,x,y,maxWidth); //繪製文字
  
  ctx.rect(x,y,width,height); //繪製矩形
  
  ctx.clearRect(x,y,width,height);//清除矩形內像素
  
  ctx.scale(scalewidth,scaleheight);//縮放
  
  ctx.rotate(angle);//旋轉角度
  
  。。。。
  
  微信小遊戲裏,也提供了canvas對象,只不過獲取接口變了:
  
  wx.createCanvas()
  
  其他H5環境下有的Canvas API,微信環境裏也都有。
  
  1.2 動畫的原理
  
  Canvas只是一個2D的畫布,要做一個遊戲,動畫總不能少吧?要讓圖片能動起來,這又是怎麼做到的呢?請看下圖:
  
  img
  
  好吧,動畫其實就是不斷畫圖片,然後擦除,再畫圖片,再擦除的循環過程,肉眼看起來,那就是動起來了。
  
  在古老的電影膠片時代,我們看到的電影,就是一張一張連續幀的膠片組成的,最後投射到大屏幕上,變成了我們看到的電影。
  
  img
  
  1.3 動畫性能優化
  
  但是,動畫是講究幀率的,一般如果能達到每秒60幀,那就和電影一樣是很流暢的動畫效果了。計算公式:1000ms/60fps=16.67ms,這就要求我們每次動畫裏的業務邏輯計算,都要16.6ms裏完成,不能影響下一幀的顯示,否則就是卡頓,也就被人說這個遊戲好卡,性能好差了。
  
  img
  
  知道原理了,性能優化具體怎麼做呢?
  
  Canvas分層 有些遊戲中,背景是不變的,爲了提高性能,可以把遊戲背景抽離出一個單獨的canvas,這樣,在畫面發生變化的時候,不需要重繪整個背景,只需要繪製變化的那部分就可以。
  
  減少API調用 每次的ctx的api調用,都是有性能消耗的,所以,儘量減少每幀的api調用次數,具體怎麼減少,就要看業務需求了。
  
  圖片預裁剪 圖片的裁剪過程,也是有性能消耗的,我們可以把裁剪的圖片預先存起來,之後在繪製的時候,直接從內存裏拿,而不需要每次都重新裁剪。
  
  離屏繪製 直接操作上屏的canvas,性能是很差的,尤其是有單幀繪製操作很多的時候,性能下降更明顯。 這個時候,我們可以預先創建一個離屏的canvas,預先在這個canvas完成這一幀要繪製的所有動作,最後一次性的把這個離屏canvas繪製到上屏canvas中。
  
  避免阻塞 由於我們需要保證16.67ms就要完成一次幀的繪製,如果這一幀裏,邏輯運算時間超過16ms怎麼辦?那就一定會卡幀了。 我們可以使用webworker之類的技術,把耗時的邏輯計算在另一個線程執行,或者把任務進行拆解,降低每幀的耗時。
  
  當然還有很多其他更多的技巧和手段來提升canvas的性能,在這樣的情況下如果我們直接使用canvas去開發一個遊戲,還會面臨比如碰撞算法、物理系統之類的問題。 所以,如果只用canvas去開發遊戲,就如同你在吃雞遊戲裏,只拿了一把平底鍋,你怎麼和別人正面剛?
  
  所以,我們需要一把98K把自己武裝起來,那就是使用遊戲引擎開發。
  
  2. 爲什麼選擇Laya?
  
  目前支持微信小遊戲的引擎,有Cocos,Egret,Laya,我們先看下三者的功能比較:
  
  img
  
  從各種支持度上來講,laya是目前支持度最好的,也據laya側的宣傳,他的性能也是最高的。(關於性能的問題,因外部水軍比較多,在沒有做實際詳細測試前,暫時不發表評價。)
  
  在公司內部,都有三種引擎的遊戲實現,下面是截止5月份的公開數據的引擎佔比:
  
  img
  
  其實三個引擎都提供了很好的支持度,一般來說,如果原先使用過Cocos實現過APP端遊戲要移植到微信小遊戲端來的,使用Cocos是最好的選擇,如果是從頭開發一款小遊戲,那還是在Egret和Laya裏選擇一款吧!
  
  3. Laya 環境搭建
  
  前面講了那麼多,都還只是前戲,只是爲了大家對遊戲的開發有個初步的瞭解,從這一節開始我們就進入正題了。
  
  到 https://www.layabox.com/ 去下載最新的版本,並進行安裝。目前有1.X版本和2.0版本。(本文使用1.7.20版本做示例)
  
  然後就可以創建一個新的遊戲項目了,我們可以現在選擇創建一個UI示例項目
  
  img
  
  [ 創建新工程 ]
  
  3.1 代碼模式
  
  當然就是給你寫代碼的地方,感覺這個編輯器,就是在VSCode的基礎上改的。連最頂上的Code標識都還在。也因爲這樣,所以才能很好的支持TypeScript。
  
  img
  
  [ 代碼模式佈局 ]
  
  爲什麼要使用TypeScript? 本文不詳細展開比較,只需要瞭解TypeScript 是Javascript的超集,因爲多了個“Type”表示他支持強類型,並且由於靜態類型化,在寫代碼的時候編輯器就能提示你的錯誤,所以更適合開發遊戲這種邏輯複雜的應用就好了。當然最終TypeScript還是會像ES6一樣,被編譯成普通的Javascript執行。但是在開發階段管理代碼來說,已經可以駕馭大型項目了。
  
  3.2 設計模式
  
  就是用來設計UI界面的地方,拖拖拽拽就可以把遊戲頁面整出來。Laya提供了好多組件,如果有需要的可以使用,當然也可以不用他的組件,自己搞自己的自定義組件。
  
  img
  
  [ 設計模式佈局 ]
  
  4. Laya的HelloWorld
  
  都說作爲一個程序員,買來文房四寶之後,寫下的第一行字,一定是“Hello World”。(我拿着公司剛發的 20週年LAMY紀念鋼筆,寫的第一行字,居然也是“Hello World”,汗~~~)
  
  4.1 遊戲初始化
  
  4.1.1.GameMain.ts
  
  首先刪掉系統剛纔默認的文件“LayaUISample.ts”,然後新建文件GameMain.ts
  
  import WebGL = Laya.WebGL;
  
  class GameMain  {
  
  constructor() {
  
  //TS或JS版本初始化微信小遊戲的適配
  
  Laya.MiniAdpter.init(true,false);
  
  //初始化佈局大小
  
  Laya.init(375,667, WebGL);
  
  //佈局方式設定
  
  Laya.stage.scaleMode = Laya.Stage.SCALE_SHOWALL;
  
  Laya.stage.screenMode = Laya.Stage.SCREEN_VERTICAL;
  
  Laya.stage.alignV = Laya.Stage.ALIGN_CENTER;
  
  Laya.stage.alignH = Laya.Stage.ALIGN_CENTER;
  
  }
  
  }
  
  new GameMain();
  
  Laya.MiniAdpter.init()是Laya提供的對小遊戲提供的適配,因爲在小程序&小遊戲環境下,並沒有Bom和DomAPI,比如,沒有window,document, 所以需要這樣一個適配器,對小遊戲的開發方式,進行兼容。
  
  4.1.2. bin/index.html
  
  修改bin目錄下的index.html ,刪掉LayaUISample.ts的引用,改爲下面的方式:
  
  <!--啓動類添加到這裏-->
  
  <!--jsfile--Main-->
  
  <script src="js/GameMain.js"></script>
  
  <!--jsfile--Main-->
  
  在index.html裏,提供了很多Laya的類庫,這些類庫,最終會被打包成合並一個code.js. 因爲微信小遊戲的體積限制,我們不需要把所有的庫都加載進來,只選擇我們需要的庫就好了,用不到的可以都刪除。
  
  4.1.3. run
  
  接下來,點擊運行,就會出現模擬器界面了。
  
  img
  
  [ 運行模擬器 ]
  
  先別管黑乎乎的一團,下面我們就要增加“Hello World”了。
  
  4.2 繪製文字
  
  4.2.1. Laya.Text
  
  再次修改GameMain的代碼如下,重點是var txt:Laya.Text = new Laya.Text();
  
  import WebGL = Laya.WebGL;
  
  class GameMain  {
  
  constructor() {
  
  //TS或JS版本初始化微信小遊戲的適配
  
  Laya.MiniAdpter.init(true,false);
  
  //初始化佈局大小
  
  Laya.init(375,667, WebGL);
  
  //佈局方式設定
  
  Laya.stage.scaleMode = Laya.Stage.SCALE_SHOWALL;
  
  Laya.stage.screenMode = Laya.Stage.SCREEN_VERTICAL;
  
  Laya.stage.alignV = Laya.Stage.ALIGN_CENTER;
  
  Laya.stage.alignH = Laya.Stage.ALIGN_CENTER;
  
  //創建Text對象
  
  var txt:Laya.Text = new Laya.Text();
  
  //給Text的屬性賦值
  
  txt.text = "Hello World";//設定文字內容
  
  txt.color = "#ffffff"; //設定顏色
  
  txt.fontSize=20; //設定字體大小
  
  txt.pos(100,200); //設定位置
  
  //將Text對象添加到舞臺
  
  Laya.stage.addChild(txt);
  
  }
  
  }
  
  new GameMain();
  
  在上面的代碼中,我們給Stage舞臺上,添加了Text對象,然後點擊運行
  
  img
  
  啊哦,傳說中的HelloWorld終於出現了
  
  4.3 繪製圖片
  
  4.3.1 loadImage
  
  Laya的Sprite提供了一個非常簡單的loadImage方法,可以即時加載圖片並加載到舞臺上。
  
  //設置舞臺背景色
  
  Laya.stage.bgColor="#1e83e8";
  
  //創建img Sprite精靈
  
  var img:Laya.Sprite = new Laya.Sprite();
  
  //加載顯示圖片,座標位於100,50,並設置寬高 130*108
  
  img.loadImage("demo/paratrooper.jpg",100,50,130,108);
  
  //把圖片添加到舞臺
  
  Laya.stage.addChild(img);
  
  預覽如下,是不是很簡單?
  
  img
  
  但是這個方法,其實並不實用,在真實項目中,一般會有很多圖片,我們不會一張一張圖片的去加載,而是預先加載好,再去顯示圖片。也就是我們常常在遊戲主界面看到的進度條,其實就是在加載資源。
  
  4.3.2 資源預加載
  
  Laya提供一個資源加載器:Laya.loader ,來解決加載的問題。我們把上面的代碼再修改下,實現先加載完圖片,然後再繪製圖片。
  
  private imgPath1:string="demo/paratrooper.jpg";
  
  private imgPath2:string="demo/shell.jpg";
  
  constructor() {
  
  //.....省略N行代碼
  
  this.renderImage();
  
  //....省略N行代碼
  
  }
  
  renderImage():void{
  
  //定義圖片路徑集合
  
  var resArray=[
  
  {url:this.imgPath1,type:Laya.Loader.IMAGE},
  
  {url:this.imgPath2,type:Laya.Loader.IMAGE}
  
  ]
  
  //使用加載器加載圖片路徑
  
  Laya.loader.load(resArray,Laya.Handler.create(this,this.onLoadComplete),Laya.Handler.create(this,this.onLoadProgress))
  
  }
  
  //加載完成後,把圖片繪製到畫布上
  
  onLoadComplete():void{
  
  console.log("加載完成");
  
  var img1:Laya.Sprite = new Laya.Sprite();
  
  img1.graphics.drawTexture(www.yigouyule2.cn  Laya.loader.getRes(this.imgPath1),100,50,100,100);
  
  Laya.stage.addChild(img1);
  
  var img2:Laya.Sprite =www.dasheng178.com/ new Laya.Sprite();
  
  img2.graphics.drawTexture(Laya.loader.getRes(this.imgPath2),100,300,100,100);
  
  Laya.stage.addChild(img2);
  
  }
  
  //這裏可以獲取到加載的進度,以後可以製作進度條
  
  onLoadProgress(percent:number):void{
  
  console.log("percent->"+percent);
  
  }
  
  4.3.3 圖集
  
  只是預加載圖片還不夠,實際場景由於有很多小圖片,所以我們可以把這些小圖片拼合成圖集,這就類似在前端在做性能優化的有時候所使用的css sprite精靈圖,這樣製作成圖集,不但加載性能更高,而且也更便於製作幀動畫。
  
  圖集的加載類似這樣:
  
  var resArray=[
  
  {url:"res/atlas/demo.atlas",type:Laya.Loader.ATLAS},
  
  ]
  
  Laya.loader.load(resArray,Laya.Handler.create(this,this.onLoadComplete),Laya.Handler.create(this,this.onLoadProgress))
  
  和之前的圖片加載時Laya.Loader.IMAGE不同的是,type變成了Laya.Loader.ATLAS。
  
  那圖集怎麼製作呢?還有,大量的遊戲界面,真的就靠手動一張圖片一張圖片的顯示嗎? 當然不!因爲我們接下來該瞭解下UI編輯器了。
  
  5. UI編輯器
  
  UI編輯器,當然是用來編輯UI的,大多數的客戶端程序開發環境,都有類似的UI編輯器。點擊左側的
  
  img
  
  圖標,進入UI編輯器模式,如下圖:
  
  img
  
  具體UI編輯器的功能介紹,建議還是看官方文檔,這裏就不贅述了。
  
  5.1創建UI
  
  因爲我們創建的是默認UI項目,所以UI編輯器裏,有一個TestPage.ui,可以不用管他,我們創建一個自己的UI。 點擊 文件->新建文件
  
  img
  
  進入新建頁面窗口,頁面類型有View 和Dialog兩種,因爲這裏我們做的是整個頁面,所以選View。如果你有興趣去看源碼,其實Dialog也是基於View實現的,只不過多了Dialog的一些特性。
  
  img
  
  如果對這個view後面還有邏輯代碼要寫,建議勾選“創建邏輯類”,這樣就會自動在View目錄下自動創建一個和UI對應的GamePage.ts
  
  img
  
  [ 新建頁面UI ]
  
  5.2 導入資源
  
  在assets目錄下,新建一個demo資源目錄,把需要的圖片都扔進去,然後在UI編輯器的資源面板最下方找找到刷新按鈕
  
  img
  
  ,新增資源圖片後,一定要記得點下刷新,否則資源面板的內容不會自動刷新。
  
  img
  
  只要是demo文件下的圖片,都會被自動打包成圖集,路徑就是 res/atlas/demo.atlas。 不知道有沒有同學發現,在上面的圖片中,有部分資源顯示“不打包”,這是什麼原因的?
  
  點擊文件-》項目設置,我們會看到圖集限制了能被打入圖集的單圖的最大寬高,和最終圖集的最大寬高,默認標準可以自行修改。超過這個圖集標準的圖片,就不會打包到圖集中去,就需要手動加載了。
  
  img
  
  [ 請在這裏填寫圖片描述 ]
  
  5.3 編輯UI
  
  編輯頁面功能,會用ppt的,應該都會用了,拖個圖片誰不會?直接把資源管理器的圖片,拖到右側場景編輯器裏。這次我們拖了一個藍天白雲的背景,並在最下方放了一個大炮,看起來還有點意思。
  
  img
  
  頂部有一排圖標,是用來協助對齊圖片用的,提供了頂部對齊,底部對齊,左對齊,右對齊,中線對齊等等,如果圖片很多,用這個對齊就很方便了。
  
  img
  
  右側的屬性欄,就比較常用了。 var這裏,你可以給你拖進來的圖片組件,給個變量名,這個變量名,最後會在之前自動生成的邏輯類裏用到。我們把大炮定個變量名“pao”,後面會用到;x,y,width,height這裏,就是座標和寬高,就不用多說了吧?
  
  img
  
  5.4 導出UI
  
  UI做好以後,有個重要的工作,就是千萬別忘記導出。很多初學者,經常會忘記這點。導出UI,纔會重新生成圖集和UI相關設置。
  
  img
  
  導出以後,我們看laya/pages/GamePage.ui 文件,不用管裏面的詳細內容,裏面就是剛纔我們拖拽圖片,自動生成的響應配置文件。
  
  img
  
  5.5 使用UI
  
  下面我們要把剛纔編輯的GamePage顯示出來,那就回過頭來,再次修改GameMain.ts
  
  class GameMain  {
  
  //定義靜態變量 gamePageView
  
  public static gamePageView:view.GamePage;
  
  constructor(www.gcyL157.com) {
  
  //...
  
  this.renderImage();
  
  //...
  
  }
  
  renderImage():void{
  
  //資源加載
  
  var resArray=[
  
  {url:"res/atlas/demo.atlas",type:Laya.Loader.ATLAS},
  
  ]
  
  Laya.loader.load(resArray,Laya.Handler.create(www.quwanyule157.comthis,this.onLoadComplete),Laya.Handler.create(this,this.onLoadProgress))
  
  }
  
  onLoadComplete(www.mcyllpt.com):www.quwanyule157.com void{
  
  //初始化view
  
  GameMain.gamePageView = new view.GamePage();
  
  //添加到舞臺
  
  Laya.stage.addChild(GameMain.gamePageView);
  
  }
  
  }
  
  new GameMain();
  
  運行一下,主界面遊戲背景,和大炮都已經架設好了,好的開端,就是成功的一半了。
  
  img
  
  接下來,根據最初的牛逼策劃,我們要像pubgm一樣,讓傘兵從天下掉下來,怎麼實現?接着看動畫部分吧!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章