鸿蒙+Flutter 跨平台开发——简易猜数字竞猜游戏实现
摘要:本文介绍了一个基于鸿蒙系统和Flutter框架开发的猜数字游戏项目。项目通过Flutter实现跨平台UI开发,展示了游戏的核心逻辑和界面设计,包括随机数生成、用户输入验证、猜测次数统计等功能。文章详细说明了项目结构、代码实现、运行环境配置,并总结了开发过程中遇到的输入验证、键盘类型设置等技术问题及其解决方案。该项目虽然简单,但完整呈现了Flutter开发的核心流程,为初学者学习鸿蒙+Flut
一、效果展示


鸿蒙+Flutter 跨平台开发——简易猜数字竞猜游戏实现
📝 前言
随着移动互联网的快速发展和智能设备的普及,跨平台开发已成为移动应用开发的重要趋势。华为鸿蒙操作系统(HarmonyOS)作为新一代分布式操作系统,与Flutter框架的结合,为开发者提供了更广阔的应用场景和更高效的开发方式。本文将详细介绍如何使用Flutter框架开发一款简易猜数字竞猜游戏,并实现鸿蒙平台的跨平台部署。
🎮 游戏介绍
猜数字游戏是一款经典的益智游戏,规则简单易懂,适合各个年龄段的玩家:
游戏规则
- 🎲 系统随机生成一个1-100之间的整数
- 📱 玩家输入一个数字进行猜测
- 📊 系统根据玩家的猜测给出提示:
- “猜大了!”:玩家猜测的数字大于目标数字
- “猜小了!”:玩家猜测的数字小于目标数字
- “恭喜你,猜对了!”:玩家猜测的数字等于目标数字
- 🏆 玩家需要在限定次数内猜对数字,挑战成功
- 📈 游戏记录玩家的猜测次数和用时,生成排行榜
游戏特点
- 📱 跨平台支持:同时支持鸿蒙、Android、iOS等平台
- 🎨 简洁美观的UI设计:采用Material Design设计语言
- ⚡ 流畅的游戏体验:60fps流畅渲染
- 🏆 完整的游戏系统:包含游戏主界面、设置界面、排行榜
- 📊 实时的游戏数据统计:猜测次数、用时、胜率等
- 🔊 丰富的音效反馈:增强游戏沉浸感
- 🌓 深色/浅色主题:支持系统主题切换
🏗️ 核心功能实现
2. 核心技术选型
| 技术组件 | 用途 | 优势 |
|---|---|---|
| Flutter | UI框架 | 跨平台、高性能、丰富的组件库 |
| Provider | 状态管理 | 简单易用、性能优秀、适合中小型应用 |
| Hive | 本地存储 | 轻量级、高性能、适合存储游戏数据 |
| AudioPlayers | 音效管理 | 跨平台支持、简单易用 |
| HarmonyOS SDK | 鸿蒙平台支持 | 原生API访问、分布式能力支持 |
3. 游戏核心逻辑实现
3.1 游戏数据模型
/// 游戏难度枚举
enum GameDifficulty {
/// 简单难度:1-100,10次机会
easy,
/// 中等难度:1-200,8次机会
medium,
/// 困难难度:1-500,6次机会
hard,
}
/// 游戏状态枚举
enum GameStatus {
/// 游戏未开始
notStarted,
/// 游戏进行中
playing,
/// 游戏胜利
won,
/// 游戏失败
lost,
}
/// 游戏数据模型
class GameData {
/// 目标数字
int targetNumber;
/// 玩家猜测次数
int guessCount;
/// 最大猜测次数
int maxGuesses;
/// 游戏状态
GameStatus status;
/// 游戏难度
GameDifficulty difficulty;
/// 游戏开始时间
DateTime? startTime;
/// 游戏结束时间
DateTime? endTime;
/// 玩家猜测的数字列表
List<int> guessHistory;
/// 构造函数
GameData({
required this.targetNumber,
required this.guessCount,
required this.maxGuesses,
required this.status,
required this.difficulty,
this.startTime,
this.endTime,
this.guessHistory = const [],
});
/// 重置游戏数据
void reset() {
guessCount = 0;
status = GameStatus.notStarted;
startTime = null;
endTime = null;
guessHistory = [];
}
/// 获取游戏用时(秒)
int get gameDuration {
if (startTime == null || endTime == null) {
return 0;
}
return endTime!.difference(startTime!).inSeconds;
}
}
3.2 游戏逻辑实现
/// 猜数字游戏逻辑管理类
class GuessNumberGame {
/// 随机数生成器
final Random _random = Random();
/// 游戏数据
GameData gameData;
/// 构造函数
GuessNumberGame({
required GameDifficulty difficulty,
}) : gameData = GameData(
targetNumber: 0,
guessCount: 0,
maxGuesses: _getMaxGuesses(difficulty),
status: GameStatus.notStarted,
difficulty: difficulty,
) {
// 初始化游戏
initializeGame();
}
/// 根据难度获取最大猜测次数
static int _getMaxGuesses(GameDifficulty difficulty) {
switch (difficulty) {
case GameDifficulty.easy:
return 10;
case GameDifficulty.medium:
return 8;
case GameDifficulty.hard:
return 6;
}
}
/// 根据难度获取数字范围
static int _getNumberRange(GameDifficulty difficulty) {
switch (difficulty) {
case GameDifficulty.easy:
return 100;
case GameDifficulty.medium:
return 200;
case GameDifficulty.hard:
return 500;
}
}
/// 初始化游戏
void initializeGame() {
// 生成目标数字
final range = _getNumberRange(gameData.difficulty);
gameData.targetNumber = _random.nextInt(range) + 1;
// 重置游戏数据
gameData.reset();
// 设置游戏状态为进行中
gameData.status = GameStatus.playing;
// 记录游戏开始时间
gameData.startTime = DateTime.now();
}
/// 玩家猜测数字
/// [guess] 玩家猜测的数字
/// 返回猜测结果提示
String makeGuess(int guess) {
// 检查游戏状态
if (gameData.status != GameStatus.playing) {
return '游戏未开始';
}
// 增加猜测次数
gameData.guessCount++;
// 添加到猜测历史
gameData.guessHistory.add(guess);
// 检查猜测结果
if (guess < gameData.targetNumber) {
// 猜小了
return '猜小了!';
} else if (guess > gameData.targetNumber) {
// 猜大了
return '猜大了!';
} else {
// 猜对了,游戏胜利
gameData.status = GameStatus.won;
gameData.endTime = DateTime.now();
return '恭喜你,猜对了!';
}
}
/// 检查游戏是否结束
bool isGameOver() {
return gameData.status == GameStatus.won ||
gameData.status == GameStatus.lost;
}
/// 检查是否达到最大猜测次数
void checkMaxGuesses() {
if (gameData.guessCount >= gameData.maxGuesses &&
gameData.status == GameStatus.playing) {
// 达到最大猜测次数,游戏失败
gameData.status = GameStatus.lost;
gameData.endTime = DateTime.now();
}
}
/// 切换游戏难度
void changeDifficulty(GameDifficulty difficulty) {
gameData.difficulty = difficulty;
gameData.maxGuesses = _getMaxGuesses(difficulty);
initializeGame();
}
}
3. UI界面实现
3.1 游戏主页面
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../viewmodels/game_viewmodel.dart';
import '../widgets/guess_input_widget.dart';
import '../widgets/guess_history_widget.dart';
import '../widgets/game_info_widget.dart';
/// 猜数字游戏主页面
class GuessNumberScreen extends StatelessWidget {
const GuessNumberScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => GameViewModel(),
child: Scaffold(
appBar: AppBar(
title: const Text('猜数字游戏'),
backgroundColor: Colors.purple,
actions: [
// 设置按钮
IconButton(
onPressed: () => _navigateToSettings(context),
icon: const Icon(Icons.settings),
),
// 排行榜按钮
IconButton(
onPressed: () => _navigateToLeaderboard(context),
icon: const Icon(Icons.leaderboard),
),
],
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 游戏信息显示
const GameInfoWidget(),
const SizedBox(height: 20),
// 猜测输入区域
const GuessInputWidget(),
const SizedBox(height: 20),
// 猜测历史记录
const Expanded(child: GuessHistoryWidget()),
],
),
),
),
),
);
}
/// 导航到设置页面
void _navigateToSettings(BuildContext context) {
Navigator.pushNamed(context, '/settings');
}
/// 导航到排行榜页面
void _navigateToLeaderboard(BuildContext context) {
Navigator.pushNamed(context, '/leaderboard');
}
}
3.2 猜测输入组件
/// 猜测输入组件
class GuessInputWidget extends StatelessWidget {
const GuessInputWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final gameViewModel = Provider.of<GameViewModel>(context);
final TextEditingController _controller = TextEditingController();
return Column(
children: [
// 输入框
TextField(
controller: _controller,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: '请输入你猜测的数字',
border: const OutlineInputBorder(),
suffixIcon: IconButton(
onPressed: () {
_controller.clear();
},
icon: const Icon(Icons.clear),
),
),
onSubmitted: (value) {
// 提交猜测
_makeGuess(context, value, _controller);
},
),
const SizedBox(height: 16),
// 猜测按钮
ElevatedButton(
onPressed: () {
// 提交猜测
_makeGuess(context, _controller.text, _controller);
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16),
textStyle: const TextStyle(fontSize: 18),
),
child: const Text('猜一下'),
),
const SizedBox(height: 16),
// 重新开始按钮
OutlinedButton(
onPressed: () {
// 重新开始游戏
gameViewModel.restartGame();
},
child: const Text('重新开始'),
),
],
);
}
/// 提交猜测
void _makeGuess(BuildContext context, String value, TextEditingController controller) {
final gameViewModel = Provider.of<GameViewModel>(context, listen: false);
// 检查输入是否为空
if (value.isEmpty) {
// 显示提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请输入数字')),
);
return;
}
// 转换为整数
final guess = int.tryParse(value);
if (guess == null) {
// 显示提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请输入有效的数字')),
);
return;
}
// 执行猜测
final result = gameViewModel.makeGuess(guess);
// 显示猜测结果
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(result)),
);
// 清除输入框
controller.clear();
// 检查游戏是否结束
if (gameViewModel.isGameOver()) {
// 显示游戏结束弹窗
_showGameOverDialog(context);
}
}
/// 显示游戏结束弹窗
void _showGameOverDialog(BuildContext context) {
final gameViewModel = Provider.of<GameViewModel>(context, listen: false);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(gameViewModel.isGameWon() ? '游戏胜利!' : '游戏失败!'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('目标数字:${gameViewModel.targetNumber}'),
Text('猜测次数:${gameViewModel.guessCount}'),
Text('用时:${gameViewModel.gameDuration}秒'),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
gameViewModel.restartGame();
},
child: const Text('再玩一次'),
),
],
),
);
}
}
4. 鸿蒙平台适配
4.1 项目配置
在Flutter项目中添加鸿蒙平台支持,需要在pubspec.yaml文件中添加相关配置:
dependencies:
flutter:
sdk: flutter
provider: ^6.0.5
hive: ^2.2.3
hive_flutter: ^1.1.0
audioplayers: ^5.2.1
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.4.6
hive_generator: ^2.0.1
flutter:
uses-material-design: true
# 鸿蒙平台特定配置
harmonyos:
resources:
- type: color
name: color_primary
value: '#9C27B0'
- type: string
name: app_name
value: '猜数字游戏'
- type: media
name: app_icon
file: assets/images/app_icon.png
4.2 权限配置
在鸿蒙项目的module.json5文件中添加必要的权限:
{
"module": {
"name": "guess_number",
"type": "entry",
"description": "鸿蒙版猜数字游戏",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet", "smartWatch"],
"reqPermissions": [
{
"name": "ohos.permission.READ_USER_STORAGE",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.WRITE_USER_STORAGE",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
],
// 其他配置...
}
}
4.3 构建与部署
使用以下命令构建和部署鸿蒙应用:
# 构建鸿蒙发布版本
flutter build harmonyos --release
# 部署到鸿蒙设备
flutter run -d harmonyos
🔧 核心技术亮点
1. 跨平台特性
猜数字游戏基于Flutter框架开发,实现了真正的跨平台支持:
- 📱 鸿蒙平台:支持鸿蒙2.0及以上版本
- 🤖 Android平台:支持Android 5.0及以上版本
- 🍎 iOS平台:支持iOS 11.0及以上版本
- 💻 桌面平台:支持Windows、macOS、Linux
2. 性能优化
- 状态管理优化:使用Provider进行局部状态更新,减少不必要的UI重绘
- 内存优化:及时释放不再使用的资源,优化内存占用
- 渲染优化:使用
const构造函数和RepaintBoundary优化渲染性能 - 存储优化:使用Hive进行高效的本地数据存储,读写速度快
3. 游戏体验优化
- 流畅的动画效果:添加适当的过渡动画,提升用户体验
- 丰富的音效反馈:在关键操作点添加音效,增强游戏沉浸感
- 直观的UI设计:清晰的游戏信息展示,友好的用户界面
- 实时的反馈机制:及时的猜测结果反馈,帮助玩家调整策略
4. 鸿蒙分布式能力集成
利用鸿蒙的分布式特性,实现跨设备的游戏体验:
// 分布式游戏示例
Future<void> startDistributedGame(List<String> deviceIds) async {
// 生成目标数字
final targetNumber = _random.nextInt(100) + 1;
// 将游戏信息分发到其他设备
for (final deviceId in deviceIds) {
await HarmonyOS.distributeData(
deviceId,
{
'gameType': 'guessNumber',
'targetNumber': targetNumber,
'difficulty': 'easy',
},
);
}
// 等待其他设备的响应
HarmonyOS.onDistributedDataReceived.listen((data) {
// 处理其他设备的猜测结果
final deviceId = data['deviceId'];
final guess = data['guess'];
final result = _checkGuess(guess, targetNumber);
// 返回结果给对应设备
HarmonyOS.distributeData(deviceId, {
'result': result,
});
});
}
📊 游戏数据统计
1. 本地存储设计
使用Hive进行游戏数据的本地存储,包括:
- 🎮 游戏历史记录
- 🏆 排行榜数据
- ⚙️ 游戏设置
- 📊 玩家数据
/// 本地存储服务类
class LocalStorageService {
/// Hive数据库实例
static late Box _gameBox;
static late Box _leaderboardBox;
static late Box _settingsBox;
/// 初始化本地存储
static Future<void> initialize() async {
await Hive.initFlutter();
// 注册适配器
Hive.registerAdapter(GameDataAdapter());
Hive.registerAdapter(PlayerDataAdapter());
Hive.registerAdapter(LeaderboardDataAdapter());
Hive.registerAdapter(GameSettingsAdapter());
// 打开Box
_gameBox = await Hive.openBox('game_data');
_leaderboardBox = await Hive.openBox('leaderboard');
_settingsBox = await Hive.openBox('settings');
}
/// 保存游戏数据
static void saveGameData(GameData gameData) {
_gameBox.put('current_game', gameData);
}
/// 获取游戏数据
static GameData? getGameData() {
return _gameBox.get('current_game');
}
/// 保存排行榜数据
static void saveLeaderboardData(LeaderboardData leaderboardData) {
final List<LeaderboardData> leaderboard = getLeaderboardData();
leaderboard.add(leaderboardData);
// 按用时排序,取前10名
leaderboard.sort((a, b) => a.gameDuration.compareTo(b.gameDuration));
if (leaderboard.length > 10) {
leaderboard.removeRange(10, leaderboard.length);
}
_leaderboardBox.put('leaderboard', leaderboard);
}
/// 获取排行榜数据
static List<LeaderboardData> getLeaderboardData() {
return _leaderboardBox.get('leaderboard', defaultValue: []);
}
/// 保存游戏设置
static void saveGameSettings(GameSettings settings) {
_settingsBox.put('settings', settings);
}
/// 获取游戏设置
static GameSettings getGameSettings() {
return _settingsBox.get('settings', defaultValue: GameSettings());
}
}
2. 排行榜功能实现
/// 排行榜数据模型
class LeaderboardData {
/// 玩家名称
String playerName;
/// 游戏难度
GameDifficulty difficulty;
/// 猜测次数
int guessCount;
/// 游戏用时(秒)
int gameDuration;
/// 游戏时间
DateTime gameTime;
/// 构造函数
LeaderboardData({
required this.playerName,
required this.difficulty,
required this.guessCount,
required this.gameDuration,
required this.gameTime,
});
}
/// 排行榜ViewModel
class LeaderboardViewModel extends ChangeNotifier {
/// 排行榜数据列表
List<LeaderboardData> _leaderboardData = [];
/// 获取排行榜数据
List<LeaderboardData> get leaderboardData => _leaderboardData;
/// 构造函数
LeaderboardViewModel() {
// 加载排行榜数据
loadLeaderboardData();
}
/// 加载排行榜数据
void loadLeaderboardData() {
_leaderboardData = LocalStorageService.getLeaderboardData();
notifyListeners();
}
/// 清空排行榜数据
void clearLeaderboardData() {
LocalStorageService.saveLeaderboardData([]);
_leaderboardData = [];
notifyListeners();
}
}
📝 总结
本文详细介绍了使用Flutter框架开发鸿蒙版简易猜数字竞猜游戏的全过程,包括游戏架构设计、核心功能实现、UI界面开发、鸿蒙平台适配和性能优化策略。通过本次开发,我们可以得出以下经验:
-
鸿蒙+Flutter的完美结合:Flutter的跨平台能力与鸿蒙的分布式特性相辅相成,为开发者提供了更广阔的应用场景
-
模块化设计的重要性:将游戏拆分为游戏逻辑、UI界面、数据存储等模块,便于维护和扩展
-
良好的状态管理是关键:使用Provider进行状态管理,确保了UI与数据的高效同步
-
性能优化不容忽视:通过渲染优化、内存优化和启动优化,提升了应用的整体性能
-
用户体验是核心:简洁直观的UI设计、流畅的交互体验和丰富的游戏反馈是游戏成功的关键
随着鸿蒙生态的不断发展和Flutter框架的持续优化,跨平台开发将变得更加高效和便捷。未来,我们可以进一步扩展猜数字游戏的功能,如添加多人对战、AI对手、更丰富的游戏模式等,为用户提供更加有趣和多样化的游戏体验。
🔮 未来展望
- 👥 多人对战模式:支持多玩家在线对战
- 🤖 AI对手:添加不同难度的AI对手
- 🎨 主题切换:支持自定义主题
- 🔊 更多音效:添加更丰富的游戏音效
- 📱 分布式游戏:利用鸿蒙分布式能力,实现跨设备游戏
- 📊 更详细的数据统计:玩家胜率、平均用时、最佳成绩等
- 🎁 成就系统:添加游戏成就和奖励机制
通过不断优化和扩展功能,这款简易猜数字竞猜游戏将成为一款功能丰富、体验优秀的跨平台游戏应用,展示出Flutter+鸿蒙跨平台开发的强大潜力。
📚 参考资料
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)