小游戏合集 (MiniGames) 是一个基于 Flutter + Flame 的多游戏合集应用,类似于《世界游戏大全51》。
- 包名:
top.z7workbench.minigames - 应用名称: 小游戏合集 (minigames)
- 目标平台: iOS, Android, Windows, macOS, Linux, Web
| 层级 | 技术 | 版本 | 用途 |
|---|---|---|---|
| 底层 | Drift | ^2.32.0 | 跨平台数据库 |
| 底层 | path_provider | ^2.1.5 | 跨平台文件路径 |
| 底层 | shared_preferences | ^2.2.3 | 轻量配置存储 |
| 中层 | Flame | ^1.19.0 | 游戏引擎 |
| 中层 | flame_audio | ^2.10.0 | 游戏音效 |
| 上层 | Flutter | Latest | UI框架 |
| 上层 | flutter_riverpod | ^2.5.1 | 状态管理 |
| 上层 | riverpod_annotation | ^2.3.5 | 代码生成 |
| 上层 | flutter_localizations | SDK | 多语言支持 |
build_runner- 代码生成riverpod_generator- Riverpod代码生成riverpod_lint- Riverpod代码检查drift_dev- Drift代码生成custom_lint- 自定义lint规则
lib/
├── data/ # 底层:数据层
│ ├── database.dart # Drift数据库主类
│ ├── tables/ # 表定义
│ │ ├── game_records.dart
│ │ ├── game_settings.dart
│ │ ├── user_progress.dart
│ │ ├── yacht_dice_saves.dart
│ │ └── twenty48_saves.dart
│ ├── daos/ # DAO层
│ │ ├── game_records_dao.dart
│ │ ├── game_settings_dao.dart
│ │ ├── user_progress_dao.dart
│ │ ├── yacht_dice_saves_dao.dart
│ │ └── twenty48_saves_dao.dart
│ └── providers/ # 数据层Providers
│ └── database_provider.dart
│
├── games/ # 中层:游戏逻辑层
│ ├── base/ # 游戏基类
│ │ ├── base_game.dart # FlameGame基类
│ │ ├── base_world.dart # World基类
│ │ ├── base_scene.dart # Scene基类
│ │ └── game_router.dart # 游戏路由
│ ├── components/ # 共享组件
│ │ ├── wooden_button.dart
│ │ ├── game_dialog.dart
│ │ ├── dice_component.dart
│ │ └── number_selector.dart
│ ├── hit_and_blow/ # 猜数字游戏
│ │ ├── hit_and_blow_game.dart
│ │ ├── components/
│ │ └── models/
│ ├── yacht_dice/ # 游艇骰子游戏
│ │ ├── yacht_dice_game.dart
│ │ ├── ai/ # AI系统
│ │ ├── components/
│ │ └── models/
│ └── guess_arrangement/ # 猜排列游戏
│ ├── models/ # 数据模型
│ │ ├── playing_card.dart # 扑克牌模型
│ │ └── guess_arrangement_state.dart # 游戏状态
│ ├── components/ # UI组件
│ │ ├── card_display.dart # 卡牌显示(带翻牌动画)
│ │ ├── card_slot.dart # 卡牌位置槽
│ │ └── result_dialog.dart # 结果对话框
│ ├── ai/ # AI系统
│ │ ├── guess_ai.dart # AI基类
│ │ ├── easy_ai.dart # 随机猜测
│ │ ├── medium_ai.dart # 规则匹配
│ │ └── hard_ai.dart # 启发式搜索
│ ├── screens/ # 游戏页面
│ │ └── start_screen.dart # 开始页面
│ ├── guess_arrangement_provider.dart # Riverpod Provider
│ └── guess_arrangement_screen.dart # 主游戏界面
│
│ └── twenty48/ # 2048游戏
│ ├── models/ # 数据模型
│ │ ├── twenty48_tile.dart # 方块模型
│ │ └── twenty48_state.dart # 游戏状态
│ ├── components/ # UI组件
│ │ ├── tile_widget.dart # 方块组件(带动画)
│ │ └── grid_widget.dart # 4x4网格容器
│ ├── screens/ # 游戏页面
│ │ ├── twenty48_start_screen.dart # 开始页面
│ │ └── twenty48_load_screen.dart # 存档页面
│ ├── twenty48_provider.dart # Riverpod Provider
│ └── twenty48_screen.dart # 主游戏界面
│
│ └── hearts/ # 红心大战游戏
│ ├── models/ # 数据模型
│ │ ├── hearts_state.dart # 游戏状态
│ │ ├── hearts_player.dart # 玩家模型
│ │ ├── hearts_card.dart # 卡牌模型
│ │ ├── trick.dart # 一轮牌
│ │ └── enums.dart # 游戏枚举
│ ├── components/ # UI组件
│ │ ├── card_widget.dart # 单张卡牌显示
│ │ ├── hand_widget.dart # 手牌显示(带高亮)
│ │ ├── trick_widget.dart # 当前一轮牌显示
│ │ ├── player_info_widget.dart # 玩家信息显示
│ │ ├── pass_phase_widget.dart # 交换手牌界面
│ │ └── scoreboard_widget.dart # 计分板
│ ├── logic/ # 游戏逻辑
│ │ ├── hearts_rules.dart # 规则验证
│ │ └── hearts_scoring.dart # 计分逻辑
│ ├── ai/ # AI系统
│ │ ├── hearts_ai.dart # AI基类
│ │ ├── easy_ai.dart # 简单难度
│ │ ├── medium_ai.dart # 中等难度
│ │ ├── hard_ai.dart # 困难难度
│ │ ├── ai_decision.dart # AI决策模型
│ │ └── card_tracker.dart # 卡牌追踪器
│ ├── utils/ # 工具类
│ │ ├── deck_utils.dart # 牌堆工具
│ │ └── card_utils.dart # 卡牌工具
│ ├── screens/ # 游戏页面
│ │ └── hearts_start_screen.dart # 开始页面
│ ├── hearts_provider.dart # Riverpod Provider
│ └── hearts_screen.dart # 主游戏界面
│
├── ui/ # 上层:UI层
│ ├── screens/ # 页面
│ │ ├── home_screen.dart
│ │ ├── settings_screen.dart
│ │ └── game_screen.dart
│ ├── widgets/ # 共享Widget
│ │ ├── game_card.dart
│ │ ├── wooden_app_bar.dart
│ │ └── theme_toggle.dart
│ └── theme/ # 主题系统
│ ├── app_theme.dart
│ ├── wooden_colors.dart
│ └── theme_provider.dart
│
├── providers/ # 全局Providers
│ ├── app_providers.dart # 统一导出
│ ├── settings_provider.dart
│ └── locale_provider.dart
│
├── l10n/ # 国际化
│ ├── app_en.arb
│ └── app_zh.arb
│
├── models/ # 共享模型
│ ├── game_type.dart
│ └── player.dart
│
├── utils/ # 工具类
│ ├── extensions.dart
│ └── constants.dart
│
├── app.dart # 应用根Widget
└── main.dart # 应用入口
- 文件: snake_case (e.g.,
game_records_dao.dart) - 类: PascalCase (e.g.,
GameRecordsDao) - 方法/变量: camelCase (e.g.,
getHighScore) - 常量: ALL_CAPS_WITH_UNDERSCORES (e.g.,
MAX_ATTEMPTS) - 私有成员: _prefix (e.g.,
_database)
使用@riverpod注解,类必须继承_$ClassName:
@riverpod
class GameState extends _$GameState {
@override
GameStateModel build() {
return GameStateModel.initial();
}
void startGame() {
state = state.copyWith(status: GameStatus.playing);
}
}@DataClassName('GameRecord')
class GameRecords extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get gameType => text().withLength(min: 1, max: 50)();
IntColumn get score => integer().withDefault(const Constant(0))();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
}class MyComponent extends PositionComponent
with RiverpodComponentMixin, HasGameReference<MyGame> {
@override
void onMount() {
addToGameWidgetBuild(() {
ref.listen(gameStateProvider, (prev, next) {
// 响应状态变化
});
});
super.onMount();
}
}<type>(<scope>): <description>
Types:
- feat: 新功能
- fix: Bug修复
- chore: 构建/配置更改
- docs: 文档更新
- test: 添加测试
- refactor: 代码重构
Scopes:
- data: 数据库/数据层
- game: 游戏引擎/游戏
- ui: Flutter UI组件
- i18n: 国际化
- theme: 主题/样式
- deps: 依赖项
示例:
feat(game): add Hit & Blow game logicfix(data): correct high score calculationchore(deps): add Flame, Riverpod, Drift dependencies
# 代码生成(必须运行)
flutter pub run build_runner build --delete-conflicting-outputs
# 持续监听生成(开发时)
flutter pub run build_runner watch --delete-conflicting-outputs
# 运行应用
flutter run
# 代码检查
flutter analyze
# 运行测试
flutter testlib/l10n/app_en.arb- 英文lib/l10n/app_zh.arb- 简体中文
// app_en.arb
{
"@@locale": "en",
"appTitle": "Mini Games",
"@appTitle": {
"description": "应用标题"
}
}// app_zh.arb
{
"@@locale": "zh",
"appTitle": "小游戏合集"
}import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Text(AppLocalizations.of(context)!.appTitle)本项目支持 3 种配色方案 × 2 种亮度模式 = 6 种主题组合:
| 配色方案 | 浅色模式 | 深色模式 |
|---|---|---|
| 木质 (Wooden) | 暖木色调(卡其色、棕色) | 深胡桃色(深棕、乌木) |
| 星空 (Starlight) | 柔和紫色、天蓝色 | 深紫色、深蓝色 |
| 森林 (Forest) | 柔和绿色、薄荷色 | 墨绿色(深森林色) |
🚨 组件开发必须适配所有 4 种主题组合!
import '../../ui/theme/theme_colors.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
// ✅ 背景色 - 自动适配木质/星空/森林 + 深色/浅色
color: context.themeBackground,
// ✅ 主要文字颜色
child: Text(
'Hello',
style: TextStyle(color: context.themeTextPrimary),
),
);
}
}// ❌ 绝对禁止!这会导致星空主题下仍显示木质颜色
Container(
color: isDark ? WoodenColors.darkBackground : WoodenColors.lightBackground,
)
// ❌ 绝对禁止!硬编码主题特定颜色
Icon(Icons.settings, color: WoodenColors.accentAmber),通过 BuildContext 扩展访问:
| 扩展属性 | 用途 | 说明 |
|---|---|---|
context.themePrimary |
主色 | AppBar、主要按钮背景 |
context.themeSecondary |
次要色 | 次要元素 |
context.themeBackground |
背景色 | Scaffold 背景 |
context.themeSurface |
表面色 | 卡片、容器背景 |
context.themeCard |
卡片色 | 卡片背景 |
context.themeAccent |
强调色 | 图标、按钮、高亮(木质=琥珀色,星空=紫色,森林=翠绿色) |
context.themeAccentSecondary |
次强调色 | 渐变、次要强调 |
context.themeTextPrimary |
主要文字 | 标题、重要文字 |
context.themeTextSecondary |
次要文字 | 描述、辅助文字 |
context.themeBorder |
边框色 | 边框、分隔线 |
context.themeShadow |
阴影色 | 阴影效果 |
context.themeOnPrimary |
主色上的文字 | AppBar 上的图标/文字 |
context.themeOnAccent |
强调色上的文字 | 强调按钮上的文字 |
context.themeDisabled |
禁用色 | 禁用状态 |
context.themeDivider |
分隔线色 | Divider |
| 场景 | 推荐做法 |
|---|---|
| AppBar 上的图标 | context.themeOnPrimary(不是 themeAccent!) |
| AppBar 上的文字 | context.themeOnPrimary |
| 游戏卡片的图标 | context.themeAccent |
| 按钮渐变 | [context.themeAccent, context.themeAccentSecondary] |
| 成功/错误/警告色 | context.themeSuccess / context.themeError / context.themeWarning |
- 木质主题:
lib/ui/theme/wooden_colors.dart - 星空主题:
lib/ui/theme/starlight_colors.dart - 森林主题:
lib/ui/theme/forest_colors.dart - 主题感知扩展:
lib/ui/theme/theme_colors.dart - 主题应用:
lib/ui/theme/app_theme.dart - 主题 Provider:
lib/ui/theme/theme_provider.dart
// 切换深色/浅色模式
ref.read(themeModeNotifierProvider.notifier).toggleTheme();
// 设置配色方案
ref.read(colorSchemeNotifierProvider.notifier).setColorScheme(ColorSchemeType.starlight);开发新组件时,必须验证:
- 使用
context.theme*扩展,而非WoodenColors.*直接引用 - 已导入
theme_colors.dart - 在 深色+木质 主题下测试
- 在 深色+星空 主题下测试
- 在 深色+森林 主题下测试
- 在 浅色+木质 主题下测试
- 在 浅色+星空 主题下测试
- 在 浅色+森林 主题下测试
- AppBar 上的图标/文字使用
themeOnPrimary - 按钮使用
WoodenButton组件(已适配主题)
以下组件已正确适配多主题,可直接使用:
WoodenButton- 按钮(支持 primary, secondary, accent, ghost 变体)WoodenAppBar- 应用栏GameCard- 游戏卡片ThemeToggle- 主题切换开关
- 在
lib/games/下创建新文件夹 - 继承
BaseMiniGame创建游戏类 - 实现必需的方法:
onLoad,onGameStart,onGameEnd - 在
GameType枚举中添加新游戏类型 - 更新
HomeScreen中的游戏列表
使用flame_riverpod集成:
class MyGame extends FlameGame with RiverpodGameMixin {
@override
Future<void> onLoad() async {
await super.onLoad();
add(MyComponent());
}
}
class MyComponent extends Component with RiverpodComponentMixin {
@override
void onMount() {
addToGameWidgetBuild(() {
ref.listen(myProvider, (prev, next) {
// 响应Provider变化
});
});
super.onMount();
}
}// 保存记录
final dao = ref.read(gameRecordsDaoProvider);
await dao.insertRecord(
GameRecordsCompanion.insert(
gameType: 'hit_and_blow',
score: Value(score),
durationSeconds: duration.inSeconds,
),
);AI位于lib/games/yacht_dice/ai/:
yacht_ai.dart- AI基类easy_ai.dart- 简单难度hard_ai.dart- 困难难度(Expectimax算法)
AI决策流程:
- 分析当前骰子状态
- 计算每个可能动作的期望值
- 选择最优动作
- 返回保留哪些骰子 + 选择哪个计分类别
AI位于lib/games/guess_arrangement/ai/:
guess_ai.dart- AI基类 + AiDecision数据类easy_ai.dart- 随机猜测medium_ai.dart- 规则匹配(基于位置推断)hard_ai.dart- 启发式搜索(概率分析)
AI决策流程:
- 分析对手已翻开的牌和猜测历史
- 根据位置推断可能的牌面(牌按大小排序)
- 计算每个猜测的期望收益
- 返回猜测位置 + 猜测点数
AI难度差异:
- Easy: 完全随机选择位置和点数
- Medium: 基于位置上下文推断(相邻已翻开牌提供边界)
- Hard: 完整概率分布计算 + 剩余牌统计 + 位置邻接分析
AI位于lib/games/hearts/ai/:
hearts_ai.dart- AI基类 + CardTracker(卡牌追踪器)easy_ai.dart- 简单难度(避免拿分)medium_ai.dart- 中等难度(策略出牌)hard_ai.dart- 困难难度(最优策略 + shoot moon判断)
AI决策流程:
- 分析当前trick状态和已出的牌
- 追踪已出现的牌(CardTracker记录每轮trick)
- 根据手牌和规则选择最优出牌
- 决策是否尝试shoot moon(全收26分)
核心机制:
- Pass阶段: 选择传递的高风险牌(如Q♠、A♠、K♠)
- 出牌策略:
- Easy: 简单避分,优先出小牌
- Medium: 策略性出牌,控制trick走向
- Hard: 深度分析,考虑shoot moon和反shoot moon
- Shoot Moon: AI会判断是否有能力全收26分,并调整策略
- 卡牌追踪: 记录每张已出牌的位置和时间,用于推断对手手牌
AI延迟: 固定1秒决策延迟,保证流畅的游戏体验
A: 更新pubspec.yaml中的平台配置,确保Drift和path_provider支持目标平台。
A: 使用Flutter DevTools,Flame提供了游戏叠加层显示调试信息。
A: 使用flame_audio包,预加载音频资源,在游戏中调用AudioPlayer.play()。
A:
- 使用
select监听Provider的特定字段 - 避免在
update中创建新对象 - 使用
Query系统高效查找组件 - 在
onRemove中清理资源
- Fork项目
- 创建功能分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'feat(game): add amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 创建Pull Request
最后更新: 2026年3月 项目状态: 活跃开发中