【Flame 學習筆記】 FlameGame:建立基於元件的遊戲架構

更新於 2024/12/01閱讀時間約 11 分鐘
raw-image
【Flame 學習筆記】系列文章目錄:連結
【Flutter 學習筆記】線上課程教學影片:連結
【Flutter 學習筆記】系列文章目錄:連結

在這篇文章中,我們將深入探討 Flutter 的 Flame 遊戲引擎中的 FlameGame 類別,並了解其如何實現一個基於元件的遊戲架構。這個架構稱為 Flame 元件系統(Flame Component System,簡稱 FCS),它透過一棵元件樹來管理遊戲中的所有元件,並負責調用這些元件的更新和渲染方法。

FlameGame 類別概述

FlameGame 類別是 Flame 引擎的核心,允許開發者透過構造函數中的 children 參數直接添加元件,或使用 addaddAll 方法在其他地方添加元件。通常,我們會將元件添加到一個名為 World 的預設世界中,這個世界可以透過 FlameGame.world 訪問,並且添加元件的方式與其他元件相同。

以下是一個簡單的 FlameGame 實作範例,展示如何在 onLoad 方法中和構造函數中添加兩個元件:

import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flutter/widgets.dart';

/// 一個渲染箱子精靈的元件,大小為 16 x 16。
class MyCrate extends SpriteComponent {
MyCrate() : super(size: Vector2.all(16));

@override
Future<void> onLoad() async {
sprite = await Sprite.load('crate.png');
}
}

class MyWorld extends World {
@override
Future<void> onLoad() async {
await add(MyCrate());
}
}

void main() {
final myGame = FlameGame(world: MyWorld());
runApp(
GameWidget(game: myGame),
);
}

注意事項

如果你在 build 方法中實例化遊戲,則每當 Flutter 樹重建時,遊戲也會被重建,這通常會比你預期的更頻繁。為了避免這種情況,你可以先創建遊戲的實例,然後在小部件結構中引用它,或者使用 GameWidget.controlled 構造函數。

遊戲循環

GameLoop 模組是遊戲循環概念的一個簡單抽象。大多數遊戲都基於兩個方法:

  • render 方法用於繪製當前遊戲狀態的畫布。
  • update 方法接收自上次更新以來的微秒數,並允許你移動到下一個狀態。

GameLoop 被所有 Flame 的遊戲實作所使用。

調整大小

每當遊戲需要調整大小時,例如當方向改變時,FlameGame 會調用所有元件的 onGameResize 方法,並將此信息傳遞給相機和視口。FlameGame.camera 控制應該在視口中心的坐標點,預設為 [0,0](Anchor.center)。

生命週期

FlameGame 的生命週期回調(如 onLoadrender 等)按以下順序被調用:

raw-image
  1. 每個 Tick 運行
  2. 添加和調整大小時運行
  3. 只運行一次
  4. 如果被移除
  5. 如果重新父化
  6. onGameResize
  7. onLoad
  8. onMount
  9. update
  10. render
  11. onRemove

FlameGame 首次添加到 GameWidget 時,生命週期方法 onGameResizeonLoadonMount 將按此順序被調用。然後,updaterender 將在每個遊戲 Tick 中按序列被調用。如果 FlameGameGameWidget 中移除,則會調用 onRemove。如果 FlameGame 被添加到新的 GameWidget,則序列將從 onGameResize 重複。

注意事項

onGameResizeonLoad 的調用順序與其他元件相反,這是為了在資源加載或生成之前計算遊戲元素的大小。

onRemove 回調可用於清理子元件和緩存數據:

@override
void onRemove() {
// 根據遊戲需求選擇性執行。
removeAll(children);
processLifecycleEvents();
Flame.images.clearCache();
Flame.assets.clearCache();
// 在遊戲被移除時執行的其他代碼。
}

注意事項

FlameGame 中,子元件和資源的清理並不會自動進行,必須明確添加到 onRemove 回調中。

除錯模式

Flame 的 FlameGame 類別提供了一個名為 debugMode 的變數,預設為 false。不過,你可以將其設置為 true 以啟用遊戲元件的除錯功能。請注意,這個變數的值會在元件添加到遊戲時傳遞,因此如果你在運行時更改 debugMode,則不會影響已添加的元件。

有關 debugMode 的更多資訊,請參考 Flame 的除錯文檔。

更改背景顏色

要更改 FlameGame 的背景顏色,你需要重寫 backgroundColor() 方法。在以下範例中,背景顏色被設置為完全透明,以便可以看到 GameWidget 背後的元件。預設背景顏色為不透明的黑色。

class MyGame extends FlameGame {
@override
Color backgroundColor() => const Color(0x00000000);
}

請注意,背景顏色在遊戲運行時無法動態更改,但如果你希望它動態變化,可以繪製一個覆蓋整個畫布的背景。

單一遊戲實例混入

如果你正在開發一個單一遊戲應用程式,可以選擇性地將 SingleGameInstance 混入應用於你的遊戲。這在構建遊戲時是一個常見的場景:有一個全螢幕的 GameWidget,其中只包含一個遊戲實例。

添加這個混入可以在某些情況下提供性能優勢。特別是,元件的 onLoad 方法在元件添加到其父元件時保證會開始執行,即使父元件尚未掛載。因此,對 parent.add(component)await 將始終保證完成元件的加載。

使用這個混入非常簡單:

class MyGame extends FlameGame with SingleGameInstance {
// ...
}

低階遊戲 API

raw-image

Game 類別是一個低階 API,當你想要實現遊戲引擎的結構功能時可以使用。Game 類別不實現任何更新或渲染功能。

這個類別還包含生命週期方法 onLoadonMountonRemove,這些方法在遊戲被加載、掛載或移除時由 GameWidget(或其他父元件)調用。onLoad 只在類別第一次添加到父元件時被調用,而 onMount(在 onLoad 之後被調用)則在每次添加到新父元件時被調用。onRemove 在類別從父元件移除時被調用。

注意事項

使用 Game 類別可以提供更大的實現自由度,但如果使用它,你將錯過 Flame 中的所有內建功能。

以下是一個 Game 實作的範例:

class MyGameSubClass extends Game {
@override
void render(Canvas canvas) {
// ...
}

@override
void update(double dt) {
// ...
}
}

void main() {
final myGame = MyGameSubClass();
runApp(
GameWidget(
game: myGame,
)
);
}

暫停/恢復/逐步執行遊戲

Flame 遊戲可以通過以下兩種方式暫停和恢復:

  1. 使用 pauseEngine 和 resumeEngine 方法。
  2. 通過更改 paused 屬性。

當遊戲被暫停時,遊戲循環將被有效地暫停,這意味著在恢復之前不會進行任何更新或新的渲染。在遊戲暫停期間,可以使用 stepEngine 方法逐幀推進遊戲執行。這在最終遊戲中可能不太有用,但在開發過程中逐步檢查遊戲狀態時非常有幫助。

背景處理

當應用程式被送到背景時,遊戲將自動暫停,並在應用程式回到前景時恢復。這種行為可以通過將 pauseWhenBackgrounded 設置為 false 來禁用。

class MyGame extends FlameGame {
MyGame() {
pauseWhenBackgrounded = false;
}
}

在當前的 Flutter 穩定版本(3.13)中,這個標誌在非移動平台(包括網頁)上實際上會被忽略。

性能追蹤混入

在優化遊戲時,追蹤每幀更新和渲染所需的時間可能會很有用。這些數據可以幫助檢測代碼中運行較快的區域,並幫助識別渲染時間較長的視覺區域。

要獲取更新和渲染時間,只需將 HasPerformanceTracker 混入添加到遊戲類別中。

class MyGame extends FlameGame with HasPerformanceTracker {
// 可以訪問 `updateTime` 和 `renderTime` 屬性。
}

總結

在這篇文章中,我們深入探討了 Flame 遊戲引擎中的 FlameGame 類別及其元件系統。透過這個系統,開發者可以輕鬆地管理遊戲中的元件,並利用遊戲循環、生命週期回調、除錯模式等功能來構建高效的遊戲應用。


avatar-img
11會員
243內容數
哈囉!歡迎光臨我的沙龍!我是 KT,一位對應用程式開發充滿熱情的開發者。在這個專屬空間,我將與您分享我在應用開發領域的深入學習心得和豐富的實戰經驗。如果您對應用程式開發技術同樣充滿好奇,渴望不斷探索新知,歡迎成為我們的會員,一起在應用程式開發的旅途上,探索更深層次的技術世界,享受學習的樂趣。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
HKT實驗室 的其他內容
本篇文章介紹 GameWidget 是 Flutter 中用於嵌入遊戲實例的 widget,能作為應用程式的根部件或嵌入其他 widget 中。它自動擴展以填滿可用空間,並提供多種結構支援功能,如加載、錯誤處理和背景裝飾。
本文介紹 Flame 遊戲引擎建議的專案結構包含標準的 Flutter 資源目錄,並新增音效(audio)、圖片(images)和磚塊(tiles)子目錄。開發者需在 pubspec.yaml 中註冊資源,並可選擇自訂資源結構,使用 AssetsCache 和 Images 來管理資源位置。
本文介紹了 Flame,一款基於 Flutter 的開源遊戲引擎,支持多平台運行(行動裝置、桌面和網頁)。雖然不如 Unity 和 Unreal 知名,但對於熟悉 Flutter 的開發者來說,學習 Flame 是值得的。本文是筆者在學習 Flame 官方文檔過程中的筆記,旨在幫助有興趣的學習者。
本篇文章介紹 GameWidget 是 Flutter 中用於嵌入遊戲實例的 widget,能作為應用程式的根部件或嵌入其他 widget 中。它自動擴展以填滿可用空間,並提供多種結構支援功能,如加載、錯誤處理和背景裝飾。
本文介紹 Flame 遊戲引擎建議的專案結構包含標準的 Flutter 資源目錄,並新增音效(audio)、圖片(images)和磚塊(tiles)子目錄。開發者需在 pubspec.yaml 中註冊資源,並可選擇自訂資源結構,使用 AssetsCache 和 Images 來管理資源位置。
本文介紹了 Flame,一款基於 Flutter 的開源遊戲引擎,支持多平台運行(行動裝置、桌面和網頁)。雖然不如 Unity 和 Unreal 知名,但對於熟悉 Flutter 的開發者來說,學習 Flame 是值得的。本文是筆者在學習 Flame 官方文檔過程中的筆記,旨在幫助有興趣的學習者。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
這篇內容,將會講解什麼是陣列,以及與陣列相關的知識。包括陣列的簡介、陣列的資料限制、陣列的維度、一維陣列、二維陣列。
Thumbnail
這篇文章介紹了網站的整體架構以及開發時所使用的工具和套件,包括 Next.js、Tailwind CSS 和 socket.io 等。文章回顧了程式碼的重構與優化,幫助開發者提高工作效率,適合希望深入瞭解前端開發和網站架構的讀者。
Thumbnail
這篇內容,將會講解什麼是「if else」,以及與「if else」相關的知識。包括if else的簡介、if、if else、else if、套娃式的if。
Thumbnail
這篇內容,將會講解什麼是表達式(Expression),什麼是陳述式(Statement)。有了這些概念,各位會更容易理解,要如何設計程式碼。
Thumbnail
這篇內容,將會講解什麼是方法,以及與方法相關的知識。包括定義Method、Method Variable 方法變數、跨區使用Method、使用函式時要注意括號。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
這篇內容,將會用一個簡單的範例,來解釋物件(Object)和實體(Instance)的差別。包括Instance的簡介、ID、物件改變會影響實體。
Thumbnail
這篇內容,將簡單介紹Asset Browser、Workspace、Inspector、Code Browser,作為入門的介面導覽。
Thumbnail
這篇內容,將教你如何開啟新的GameMaker專案,並調整畫面佈局。也會講解,為何建議用英文語系,來進行遊戲開發。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
這篇內容,將會講解什麼是陣列,以及與陣列相關的知識。包括陣列的簡介、陣列的資料限制、陣列的維度、一維陣列、二維陣列。
Thumbnail
這篇文章介紹了網站的整體架構以及開發時所使用的工具和套件,包括 Next.js、Tailwind CSS 和 socket.io 等。文章回顧了程式碼的重構與優化,幫助開發者提高工作效率,適合希望深入瞭解前端開發和網站架構的讀者。
Thumbnail
這篇內容,將會講解什麼是「if else」,以及與「if else」相關的知識。包括if else的簡介、if、if else、else if、套娃式的if。
Thumbnail
這篇內容,將會講解什麼是表達式(Expression),什麼是陳述式(Statement)。有了這些概念,各位會更容易理解,要如何設計程式碼。
Thumbnail
這篇內容,將會講解什麼是方法,以及與方法相關的知識。包括定義Method、Method Variable 方法變數、跨區使用Method、使用函式時要注意括號。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
這篇內容,將會用一個簡單的範例,來解釋物件(Object)和實體(Instance)的差別。包括Instance的簡介、ID、物件改變會影響實體。
Thumbnail
這篇內容,將簡單介紹Asset Browser、Workspace、Inspector、Code Browser,作為入門的介面導覽。
Thumbnail
這篇內容,將教你如何開啟新的GameMaker專案,並調整畫面佈局。也會講解,為何建議用英文語系,來進行遊戲開發。