Egret 遊戲開發:投籃

前段時間爲了推廣一個新的公衆號,開發了一款名爲「投籃達人」(已下線)的小遊戲,發佈上線以後獲得了不錯的效果,成功爲公衆號吸引了不少粉絲。下面就來跟你們分享下開發這款遊戲的歷程。html

需求分析

遊戲自己其實很簡單,只是一個投籃遊戲,實現籃球的投射,籃筐運動,籃球與籃筐撞擊,遊戲結束後的排行榜記錄以及公衆號的識別。但因爲遊戲是2D遊戲,卻有一個仿3D效果(籃球投出後離咱們愈來愈遠以及穿透籃網),同時要讓籃球與籃筐進行碰撞檢測且模擬一個流暢天然的反彈效果,因此須要不斷填坑。git

技術選型

考慮到開發速度,找一個成熟且文檔齊全的HTML5 遊戲開發引擎就十分重要了,在國內大多數人用的都是Cocos2d-x-js 或Egret,phaser 或 Hilo 這些缺少比較順手的開發工具就跳過了,Cocos 在網頁上的性能不太理想,因此最後選擇了Egret 2Dgithub

至於物理引擎方面,Egret 是推薦使用P2 引擎的,由於其性能相較於Box 2D 或者Matter.js 都好,不過缺點是缺少中文文檔,目前我也在進行翻譯中,地址戳 👉 P2 中文文檔 算法

實現思路

  • 僞3D 運動 canvas

    1. 近大遠小的顯示

以籃球初始位置(或底部)爲原點確立一個視覺焦點,在籃球運動的過程當中根據籃球在Y軸上的位置計算其縮放比例,計算公式以下:瀏覽器

``scale = (curY - startY) / ( endY - startY);``複製代碼

另外,在物理世界中,任何剛體都是形狀和大小都保持不變的物理模型,也就意味着,咱們能讓籃球的貼圖的縮放,但沒法讓籃球的剛體進行縮放。
爲了讓籃球和籃筐撞擊時,籃球的大小是準確的,咱們能夠根據上圖的縮放比例公式,計算籃球抵達籃筐(籃筐位置肯定,比例必然是固定的)時的比例,在初始位置讓籃球的貼圖和剛體大小保持這一比例,當籃球運動到籃筐時大小就正好是其剛體的實際大小。性能優化

  1. 籃球與籃筐的交互bash

    因爲籃球上升時,在2D 的物理世界中,籃球和籃筐其實是同一平面,球和籃筐的剛體默認會產生碰撞,同時,籃球的縱深須要在上升時大於籃筐而下落時小於籃筐;微信

    爲了解決第一個問題,能夠利用P2 提供的碰撞分組來避免碰撞。工具

    在P2 中,剛體須要一個或多個Shape 決定剛體的外形,而Shape 又具備collisionGroup 和 collisionMask 兩個屬性,前者決定了Shape 的碰撞分組,後者決定了Shape 會與哪些碰撞分組發生碰撞。須要注意的是,collisionGroup 的取值是 Math.pow(2,0) 到 Math.pow(2,32), 具體參考(Shape 的碰撞分組);

    // 建立籃球剛體的形狀
    ballShape = new p2.Circle({radius: GlobalData.ballRadius / factor}); 
    // 設置籃球的碰撞分組
    ballShape.collisionGroup = this.FLYBALL;
    // 這樣設置 collisionMask 籃球就能與籃筐交互,注意多個分組分隔的是 | 不是 ||
    ballShape.collisionMask = this.BASKET | this.GROUND;複製代碼

    所以,在籃球上升時,設置其碰撞分組爲FLYBALL,其collisionMask 爲地面,此時籃球只會和地面碰撞,不與籃筐碰撞,當下落時,將其分組設置爲DROPBALL,collisionMask 爲地面和籃筐,此時籃球就會和籃筐發生碰撞了。

    爲了解決第二個問題,思路相似,上升時將籃球的上升設置最高,下落時與籃筐交換縱深值便可;

  • 二維碼識別

    在微信網頁中,常常須要提供長按二維碼識別功能,但二維碼須要是一張實際的圖片,內嵌於Canvas 的二維碼是不支持長按識別的,爲了讓微信可以識別到圖片,只須要在Canvas 上面覆蓋一張圖片便可。示意圖以下:

覆蓋層級示意圖
覆蓋層級示意圖

在設置圖片時,大小尺寸須要根據瀏覽器尺寸和Canvas 的實際尺寸進行計算縮放,才能讓圖片看起來像是和Canvas 一塊兒的;

  • 文字複製

    遊戲需求中,須要用戶點擊按鈕複製一段文字發送給公衆號,但因爲瀏覽器對文字複製的權限不同,市面上的解決方案是使用ZeroClipBoard, 但開發時沒考慮到,使用的是 document.execCommand(‘copy’),而因爲兼容性,進行了fallback,當瀏覽器不支持時提示用戶長按選擇文字進行復制,這時也因爲Canvas 不支持文字選擇,須要將文字跟二維碼同樣處理,放置於Canvas 之上;

性能優化

  • 渲染優化

    Egret每刷新一幀的時候,會執行四步操做。在製做遊戲的時候應該清晰的記住四步操做都在幹什麼。

    1. 咱們執行了一次EnterFrame,此時,引擎會執行遊戲中的邏輯。而且拋 EnterFrame事件。
    2. 執行一個clear。將上一幀的畫面所有擦除。
    3. Egret內核會遍歷你遊戲場景中的全部DisplayObject,並從新計算全部顯示對象的transform
    4. 若是你接觸過canvas,那麼你瞭解,這一步會將全部的圖像所有draw到畫布中。

渲染示意圖
渲染示意圖

瞭解了Egret 的渲染機制以後,咱們就知道該從哪裏下手了。

首先,因爲每次都要遍歷DisplayObject, 對於不可見的對象都要進行清除,而建立對象也須要花費性能開銷,因此咱們能夠建立回收池對不可見的對象進行回收,這樣就能夠減少一部分開銷;

其次,Canvas 檢測觸摸點的方式是遍歷全部點來檢測點擊的是哪一個點,咱們設置Touch 層的時候,儘量的往上挪,而不是設置在對象上,這樣就能夠減小遍歷所產生的開銷。

另外在遊戲開發過程當中我手頭只有iOS 設備,而測試過程時發如今安卓機上存在掉幀嚴重的現象;在將畫布尺寸從640 1136 縮小至480 800 後,卡頓情況明顯好轉,猜想是因爲畫布太多會形成渲染的開銷也變大,因此能夠將畫布在可接受範圍內設置小一些,由瀏覽器縮放畫布,從而減小渲染開銷。

  • 髒矩形渲染

    對於複雜UI界面的狀況,全屏刷新算法會每秒60次不停地刷新全部UI對象,髒矩形渲染可以檢測改變的對象,只渲染改變的對象。在有髒矩形渲染的狀況下,哪改變繪製哪,極端狀況直接跳過繪製,在複雜UI界面的狀況很是容易達到滿幀。

    Egret 默認開啓了髒矩形渲染,但當全部顯示對象都在不停的動,那這種狀況下性能反而很差。此時咱們須要經過關閉髒矩形渲染

    this.stage.dirtyRegionPolicy = "off";

  • WebGL渲染

    WebGL 經過增長 OpenGL ES 2.0 的一個 JavaScript 綁定,能夠爲 HTML5 Canvas 提供硬件 3D 加速渲染。 Egret Engine2D 提供了 WebGL 渲染模式。只需開啓 WebGL 渲染,就能得到硬件加速。

    Egret 在開啓 WebGL 渲染模式下,若是瀏覽器不支持將自動切換到Canvas 渲染模式下。

相關文章
相關標籤/搜索