【基於Flutter&Flame 的飛機大戰開發筆記】展示面板及重新開始選單
theme: cyanosis highlight: xcode
前言
前面基於bloc
管理的全域性狀態已經成型。本文將會利用該資料基於Flutter的控制元件搭建遊戲的展示面板,以及關於重新開始遊戲的選單邏輯。
筆者將這一系列文章收錄到以下專欄,歡迎有興趣的同學閱讀:
面板展示
還記得之前封裝的GameView
嗎?這裡是全部邏輯,在GameWidget
之上還有一層Stack
,用於不同面板的展示。需要注意的是GameView
的父Widget
為MultiBlocProvider
,這樣它的子Widget
才能獲取得到GameStatusBloc
。
```
class GameView extends StatelessWidget {
const GameView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned.fill(
child: GameWidget(
game: SpaceGame(gameStatusBloc: context.read
生命值面板
單獨拿生命值面板來聊,其實就是常規的bloc
模式,通過BlocBuilder
來監聽GameStatusState
,更新後會觸發builder
方法重新重新整理ui。這個就是Flutter
原生層面的知識點了。
需要注意的是,這裡用了Offstage
對檢視進行隱藏和顯示,條件是上篇文章說的GameStatus
遊戲的執行狀態。
```
class LivePanel extends StatelessWidget {
const LivePanel({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder
效果
來看看面板展示的效果吧
- 生命值面板在右下角三個小飛機,監聽的是
GameStatusState.lives
。 - 還有兩個,一個是導彈道具,一個是計分。這兩個和上述的大同小異,這裡就不展開說了。
- 導彈道具面板,在左下角,順帶一提之前沒有提及這個功能,它是在遊戲中通過道具獲得,和子彈補給同理。監聽的是
GameStatusState.bombSupplyNumber
。 - 計分面板,在右上角,擊落一艘
敵機Component
就會有相應的計分。監聽的是GameStatusState.score
。
- 導彈道具面板,在左下角,順帶一提之前沒有提及這個功能,它是在遊戲中通過道具獲得,和子彈補給同理。監聽的是
GameOver與Replay
GameStatusController
當戰機Component
的生命值到0時,使GameStatusState.status == GameStatus.gameOver
。來看一下GameStatusBloc
的處理邏輯。
// class GameStatusBloc
on<PlayerLoss>((event, emit) {
if (state.lives > 1) {
emit(state.copyWith(lives: state.lives - 1));
} else {
emit(state.copyWith(lives: 0, status: GameStatus.gameOver));
}
});
在上文中,我們往Component樹
中塞多了一個叫GameStatusController
的東西。答案在這裡揭曉了,它是專門用於響應當遊戲執行狀態變化時介面變化的。
- 當GameStatusState.status == GameStatus.gameOver
時,需要先暫停遊戲的執行時(還記得Flame
有一個update
方法回撥嗎?他是依賴執行時響應的)。然後展示GameOver
選單。
- GameOver
選單會展示分數和一個Replay
按鈕。
- Replay
按鈕點選後,會重新將GameStatusState.status == GameStatus.initial
,此時恢復遊戲的執行時,與之前的遊戲開始邏輯形成閉環。
```
class GameStatusController extends Component with HasGameRef
if (parent == null) return;
parent!.removeAll(parent!.children.where((element) {
return element is Enemy || element is Supply || element is Bullet;
}));
parent!.add(gameRef.player = Player(
initPosition:
Vector2((gameRef.size.x - 75) / 2, gameRef.size.y + 100),
size: Vector2(75, 100)));
} else if (state.status == GameStatus.gameOver) {
Future.delayed(const Duration(milliseconds: 600)).then((value) {
gameRef.pauseEngine();
gameRef.overlays.add('menu_reset');
});
}
}));
}
}
``
- 還是利用
FlameBlocListener監聽
GameStatusState的變化。
-
GameStatus.gameOver時,通過
gameRef.pauseEngine()可**暫停**遊戲的執行時。這裡的
gameRef.overlays.add('menu_reset')會在檢視最上層新增一個選單。下面會講到。
-
GameStatus.initial時,通過
gameRef.resumeEngine()可**恢復**遊戲的執行時,並移除剛剛那個選單。順帶一提,這裡需要**移除部分
Component**,譬如
敵機Component、補給Component、子彈Component。還需要重新新增一個
戰機Component`,因為之前那個已經被移除了。
GameOver選單
GameWidget
提供一個overlayBuilderMap
屬性,可以傳一個key-value
。value為該檢視的builder
方法。
GameWidget(
game: SpaceGame(gameStatusBloc: context.read<GameStatusBloc>()),
overlayBuilderMap: {
'menu_reset': (_, game) {
return ResetMenu(game: game as SpaceGame);
}
},
)
需要顯示和隱藏時就像上面一樣,呼叫add/remove
方法。
```
// 顯示
gameRef.overlays.add('menu_reset');
// 隱藏
gameRef.overlays.remove('menu_reset');
``
選單類
ResetMenu,由於都是
Flutter`原生UI的基本操作,這裡就不展開了。直接看看效果吧
最後
本文記錄了飛機大戰的面板展示與重新開始選單。至此,整個遊戲就相當完整了。相關邏輯參考Flame官方的例子:flame/packages/flame_bloc。
- 用華為CameraKit實現預覽和拍照
- 重溫今日頭條螢幕適配方案
- 【基於Flutter&Flame 的飛機大戰開發筆記】展示面板及重新開始選單
- 【基於Flutter&Flame 的飛機大戰開發筆記】利用bloc管理遊戲狀態
- 【基於Flutter&Flame 的飛機大戰開發筆記】子彈升級和補給
- 【基於Flutter&Flame 的飛機大戰開發筆記】重構敵機
- 【基於Flutter&Flame 的飛機大戰開發筆記】子彈發射及碰撞檢測
- 【基於Flutter&Flame 的飛機大戰開發筆記】敵機生成器
- 【基於Flutter&Flame 的飛機大戰開發筆記】搭建專案及建立一架戰機
- 一文搞定移動端接入ncnn模型(包括Android、iOS)
- 在Android上實現Metal的計算Demo
- 移動端執行JS指令碼除錯方案-單元測試
- 為什麼Glide4.x中的AppGlideModule不應該出現在Library中
- CameraX OpenGL預覽的全新版本
-
有關Swift Codable解析成Dictionary
的一些事 - 在iOS應用上進行記憶體監控
- 體驗一下用Metal畫圖
- 在iOS上進行WebP編碼是一種怎樣的體驗之為何cpu佔用如此之高?
- 在iOS上進行WebP編碼是一種怎樣的體驗?