Open4
Flame 学習記録

公式
参考記事
色々試すリポジトリ

Flame を学ぶモチベ
- 既存の Flutter アプリに、簡易的に組み込めるゲームを、という要望があるかも知れない(妄想)ので、そこ叶えれるならやりたい。
- Flame は Flutter のウィジェットとして実装できるので
- シンプルにどんな技術か知りたい。
- いずれゲーム開発に手を出したいので、その走りになれば。
ゴール
テニスのゲーム作りたい。
とりあえずキーボード操作ではなく、アプリのタップ操作前提で(余裕があればキーボードも)。
やり始めないとスケジュール感が見えないが、とりあえず無茶に、12月中にブロック崩し作りたい。
その辺はやりながら変わってくけど、一旦このままで。
想定は、ブロック崩し => エアホッケー => テニス => オンラインゲーム対応
ラグ軽減のための試作とかやりたい
コイントスしたい

1日目(2024/12/8)
公式のチュートリアルを進める
メモ
Flutter と Flame で、クラス名の競合とかありそうなので、①Flutter と Flame の架け橋、②Flame のみの実装 、でファイル分けるのが良さそう
first_game_widget.dart
import 'package:flame/game.dart' as flame_game;
import 'package:flutter/material.dart';
import 'first_game.dart';
class FirstGameWidget extends StatelessWidget {
const FirstGameWidget({super.key});
Widget build(BuildContext context) {
return flame_game.GameWidget.controlled(
gameFactory: () {
return FirstGame();
},
);
}
}
first_game.dart
import 'package:flame/components.dart';
class FirstGame extends FlameGame {
FirstGame() : super(children: [_Image()]) {}
}
成果
Material のテーマと繋げる
ThemeData
をとる FlameGame
クラスの作成
1. abstract class MaterialFlameGame extends FlameGame {
MaterialFlameGame({
super.camera,
super.children,
required this.themeData,
});
final ThemeData themeData;
}
HasAncestor
で、子孫から参照できるようにする
InheritedWidget
みたいだね
typedef HasMaterialGame = HasAncestor<MaterialFlameGame>;
extension HasMaterialWorldReferenceEx on HasMaterialGame {
ThemeData get themeData => ancestor.themeData;
ColorScheme get colorScheme => themeData.colorScheme;
TextTheme get textTheme => themeData.textTheme;
}
material.dart
の Text
と同じような挙動をする Component
を実装
流石に DefaultTextStyle
を採用するのはちょっとズレてると思い、シンプルに bodyMedium
を実装する形
class MaterialTextComponent extends TextComponent with HasMaterialGame {
MaterialTextComponent({required super.text});
void onMount() {
super.onMount();
textRenderer = TextPaint(
style: textStyle,
);
}
TextStyle get textStyle => themeData.textTheme.bodyMedium!;
}
ダークテーマでも動くようになった。
これが意味あるかはわからん。
Component
縦に並べる宣言的な なんか命令的に並べる方法しかなかったので、縦に並ぶやつを作ってみた。
class _ColumnComponent extends Component {
_ColumnComponent({required Iterable<PositionComponent> super.children});
void onGameResize(Vector2 size) {
super.onGameResize(size);
Component? current;
for (final child in children) {
const x = 0.0;
if (child is! PositionComponent) {
throw AssertionError(
'_ColumnComponent の children には、PositionComponent を使用してください',
);
}
if (current is PositionComponent) {
child.position = Vector2(x, current.y + current.height);
} else {
child.position = Vector2(x, 0);
}
current = child;
}
}
}
class FirstGame extends FlameScaffoldBackgroundGame {
FirstGame({required super.themeData})
: super(
children: [
_ColumnComponent(
children: [
_Image(),
MaterialTextComponent.title(text: 'Panda'),
MaterialTextComponent(text: 'Panda じゃないかも'),
MaterialTextComponent(text: '🍅トマトかも'),
MaterialTextComponent(text: '🍅トマトかも'),
MaterialTextComponent(text: '🍅トマトかも'),
],
)
],

2日目(2024/12/14)
ジェスチャー、エフェクト、当たり判定らへんをちょっとずつ触っていく。
コイントスやってみたい。
成果
タップで動かすやつ
変数で距離の切り替えできた