扣丁書屋

不用 H5,閑魚 Flutter 如何玩轉小游戲?

什么是Candy引擎?

Candy 是閑魚技術團隊設計開發的一款引擎:

  • APP嵌入式的、輕量級的、易于開發、性能穩定的互動引擎;
  • 繪制系統高度融合Flutter體系,游戲場景和Flutter UI支持無縫混排;
  • 動畫系統對主流格式的支持友好且易擴展。

本文講解我們為什么要做這款引擎以及我們是如何設計這款引擎的。

緣起

目前APP內嵌小游戲一般采用H5小游戲的方式,而這個方式存在一些隱患,并不被很多應用商店推薦。因此我們需要尋找一種新的安全的方式來實現APP內嵌小游戲,并且我們希望這個方式開發友好、性能穩定、功能齊全;所以我們遵循這三點去尋找一種新的方式。

思考

我們主要通過下面三種思路來探討APP內嵌小游戲:

  • 采用Native的游戲能力

目前Native開發游戲生態并不是特別成熟,而且采用Native開發,就必須面臨雙端兩套代碼的問題,開發成本和后續維護成本都會比較高。

  • 采用游戲引擎,比如Cocos-2dx、Unity等

雖然游戲引擎目前非常成熟,但是游戲引擎一般用于開發重度游戲,所以引擎大小一般比較大,引入游戲引擎會導致包大小增幅不小。而且游戲引擎比較復雜,所以引擎啟動耗時較多,比較難做到游戲頁面秒開;游戲引擎加載進來后內存消耗都會比較大。游戲引擎和APP間的通信互動相對較為麻煩,目前沒有比較好的混合棧支持。游戲引擎的UI能力較弱,無法勝任復雜的APP UI邏輯,若采用游戲引擎開發內嵌小游戲,無法融合小游戲頁面內游戲場景和Feeds等UI。

  • 采用Flutter的輕量級互動引擎

Flutter本身是基于Skia這個2D繪制引擎實現的跨端APP解決方案,所以它天然具備2D繪制能力,所以采用Flutter來實現App內嵌小游戲存在可能。目前Flutter存在一些輕量級游戲引擎,比如Flame,這款引擎支持簡單游戲邏輯和動畫能力,同時整個游戲是以一個Widget的形式最終插入到APP中,可以讓小游戲頁面中游戲部分和UI部分完美融合。

綜上考慮,我們決定采用Flutter的輕量級互動引擎。

Flame?還是自主設計?

Flame引擎目前是Flutter生態中比較不錯的一款小游戲引擎,但是依然存在很多問題:

  • 游戲系統不完善:引擎只有Game和Componet,沒有Scene和GameObject概念,這樣會導致游戲對象嵌套復雜,對多場景不友好。
  • 引擎完全采用Canvas來實現,游戲場景中無法實現局部刷新,存在性能隱患。
  • 缺少GUI系統,場景內嵌套UI比較難。
  • 缺少手勢事件系統。
  • 動畫支持格式不主流:骨骼動畫是通過Flare支持的,不支持DragonBones。粒子動畫最近才上,對主流格式支持也不太友好。
  • 資源管理存在內存問題,資源加載后一直不會釋放。
  • 缺少機型適配能力。

基于這些考慮,我們決定重新設計一款Flutter互動引擎:

  • 對標集團的EVA引擎和業界的Unity引擎,完善游戲系統。
  • 復用Flutter局部刷新。
  • 復用Flutter UI作為GUI。
  • 復用Flutter手勢管理。
  • 實現支持主流格式的骨骼動畫和粒子動畫。
  • 復用APP資源庫(圖片庫)。
  • 實現全局750適配。

其中2-4點本質上是將互動引擎的繪制系統融合入Flutter的繪制體系中,本文下面按解決上面問題的思路依次介紹我們的引擎設計。

Candy引擎設計

框架設計

首先分析游戲化業務需要哪些能力,分析我們的業務場景,得出游戲化業務需要圖4-1所示的能力:

圖4-1 游戲化業務能力需求

拆解后,互動引擎需要有游戲系統、繪制系統、生命周期系統、GUI系統、物理系統、動畫系統、資源系統、事件系統(手勢管理)。

根據我們之前的定位,互動游戲繪制融合到Flutter繪制體系中來,基于這個思路,我們可以復用Flutter的UI系統,同時需要融合Flutter和游戲的手勢管理。最終我們得出如圖4-2所示的框架圖:

圖4-2 互動引擎架構

整個互動引擎架構共分為四部分:

  • 接口層

對外暴露的游戲接口,主要包含創建游戲、創建游戲對象、添加游戲組件等接口,同時還封裝了一些常用游戲對象、常用游戲組件的工廠接口。

  • 游戲系統

游戲世界的管理系統,主要管理Game、Scene、GameObject和Compoent間的組織關系,還控制游戲子系統和繪制系統的啟動與關閉。

  • 游戲子系統

游戲化能力補充,主要包含生命周期系統、物理系統、動畫系統和資源系統,被游戲系統調用。

  • 繪制系統

負責游戲的繪制,本引擎的繪制系統會高度和Flutter繪制邏輯融合,所以兼容了GUI系統和事件系統(手勢管理)。

游戲系統

對標Unity設計,游戲系統有下列四大元素:

  • Game:游戲類,負責整個游戲的管理,Scene的加載管理以及各子系統管理與調度。
  • Scene:游戲場景類,負責游戲場景中各游戲對象的管理。
  • GameObject:游戲對象類,游戲世界中游戲對象的最小單位,游戲世界中的任何物體都是GameObject。
  • Component:游戲組件類,表示游戲對象的能力屬性,比如SpriteComponent表示精靈組件,表示繪制精靈的能力。

GameObject通過組合Component的形式來讓自己擁有各種能力,不同的組合讓GameObject相互之間不一樣。整個游戲系統的組織關系如圖4-3所示:

圖4-3 游戲組織形式

生命周期

對標Unity和Flutter特性,我們設計了如表4-1所示的生命周期,共有八個回調,基本可以滿足互動游戲業務開發。

表4-1 生命周期

渲染系統

基于融合Flutter繪制體系思考,我們就不能全盤用Canvas來做整個游戲的繪制管理,我們需要將游戲對象和Flutter的繪制對象RenderObject結合起來,如圖4-4所示:

圖4-4 渲染映射

首先是Game的對象數和Flutter的三顆樹有效融合,所以每一個GameObject必須對應一個Widget、Element和RenderObject。

融合過程主要需要解決以下問題:

  • 游戲的坐標系與Flutter的布局轉換融合。
  • 動態添加和刪除游戲對象的處理。
  • 動態修改游戲繪制深度的處理。
  • Flutter Inspector對游戲對象的支持。

整個繪制融合相對復雜,需要解決很多BadCase,后續會另撰文詳述互動引擎繪制融合Flutter繪制體系的過程,本文不再贅述。

GUI系統

由于繪制已經融合到Flutter體系,GameObject都會對應Widget,所以我們可以設計一個特殊的GameObject,支持插入一段Flutter Widget樹,這樣我們就不需要另外實現GUI了,復用Flutter UI作為GUI即可。這個邏輯和繪制融合思路比較一致,將插入的Widget樹作為GUIWidget的孩子即可,在GUIRenderObject中打通layout、paint和hitTest邏輯即可。

這里給一段我們GUI的示例實例代碼,開發過程相對簡單:

final GUIObject gui = IdleFishGame.createGUI(
  'gui',
  child: GestureDetector(
    child: Container(
      width: 100.0,
      height: 60.0,
      decoration: BoxDecoration(
        color: const Color(0xFFA9CCE3),
        borderRadius: const BorderRadius.all(
          Radius.circular(10.0),
        ),
      ),
      child: const Center(
        child: Text(
          'Flutter UI示例',
          style: TextStyle(
            fontSize: 14.0,
          ),
        ),
      ),
    ),
    behavior: HitTestBehavior.opaque,
    onTap: () {
      print('UI被點擊了');
    },
  ),
  position: Position(100, 100),
);
game.scene.addChild(gui);

事件系統

在繪制融合到Flutter體系的基礎上,我們融合了事件系統,增加了手勢處理組件GestureBoxComponent,如圖4-5所示:

圖4-5 手勢競技

整個融合過程分下列幾步:

  1. GestureBoxComponent將開發者注冊手勢回調方法注冊到手勢識別器中。
  2. GameObject對應的RenderObject復寫hitTest邏輯,按Flutter規范來處理點擊的hitTest。通過GestureBoxComponent來判斷點擊是否該被消費。
  3. GameObject復寫handEvent來將點擊事件傳遞給GestureBoxComponent消費。
  4. GestureBoxComponent收到點擊事件后,傳遞給手勢識別器處理。
  5. 手勢識別器在將點擊傳給手勢競技場開始手勢競技,最終將勝出的手勢返回手勢識別器,最終返回并做出手勢事件響應,當然這一步屬于Flutter邏輯了。

動畫系統

我們目前動畫主要支持骨骼動畫和粒子動畫,骨骼動畫資源目前支持DragonBones,粒子動畫資源目前支持EgretFeather。

資源系統

目前互動引擎的資源系統相對簡單,本文就簡單介紹下。資源系統的設計思路是復用APP的資源系統,確保整個APP只有一份資源庫,減少內存開銷和增大資源復用率。資源系統架構如圖4-6所示,在游戲系統和資源系統中間增加了一層代理,兼容APP資源系統和兜底資源系統。若我們沒有注冊APP的資源系統,系統會自動調用兜底的資源系統。

兜底資源系統目前分兩部分:

兜底圖片庫,復用Flutter的ImageCache,復用Flutter的能力做內存管理。

動畫JSON資源管理,目前只實現了JSON讀取邏輯,由于JSON復用性不高,所以目前并沒有實現緩存管理。

圖4-6 資源系統

目前資源系統沒有做遠程加載和預加載的能力,這部分在我們的后續規劃中,后續我們再撰文分享具體設計實現。

說在最后

本文主要講述了Candy互動引擎的設計,而我們在設計實現過程中遇到了很多問題,如發現了Flutter在繪制過程中存在一定的內存泄露,內存回收不及時等,我們后續會詳述這些問題的排查與解決,同時還會對Candy引擎的性能與穩定性方面做詳細測試分析。


https://mp.weixin.qq.com/s/v9drdzEm3vrNHkbJYxjhZg

最多閱讀

如何有效定位Flutter內存問題? 1年以前  |  11725次閱讀
Flutter的手勢GestureDetector分析詳解 3年以前  |  7686次閱讀
Flutter插件詳解及其發布插件 3年以前  |  6371次閱讀
在Flutter中添加資源和圖片 3年以前  |  5201次閱讀
Flutter 狀態管理指南之 Provider 3年以前  |  4388次閱讀
發布Flutter開發的iOS程序 3年以前  |  4365次閱讀
Flutter for Web詳細介紹 3年以前  |  4229次閱讀
在Flutter中發起HTTP網絡請求 3年以前  |  4005次閱讀
使用Inspector檢查用戶界面 3年以前  |  3923次閱讀
Flutter Widget框架概述 3年以前  |  3301次閱讀
Flutter路由詳解 3年以前  |  3141次閱讀
JSON和序列化 3年以前  |  3060次閱讀
Flutter框架概覽 3年以前  |  3025次閱讀
推薦5個Flutter重磅開源項目! 1年以前  |  2983次閱讀
為Flutter應用程序添加交互 3年以前  |  2982次閱讀
使用自定義字體 3年以前  |  2878次閱讀
處理文本輸入 3年以前  |  2870次閱讀
編寫國際化Flutter App 3年以前  |  2868次閱讀

手機掃碼閱讀
18禁止午夜福利体验区,人与动人物xxxx毛片人与狍,色男人窝网站聚色窝
<蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>