鸿蒙+flutter 跨平台开发——简易井字棋小游戏实现
随着鸿蒙操作系统的快速发展,越来越多的开发者开始关注鸿蒙平台的应用开发。Flutter作为一款优秀的跨平台UI框架,也在鸿蒙平台上得到了良好的支持。本文将介绍如何使用Flutter框架开发一款适合鸿蒙平台的井字棋小游戏,通过实际项目学习Flutter在鸿蒙平台上的开发流程和技术要点。井字棋(Tic-Tac-Toe)是一款经典的双人对战游戏,规则简单易懂,非常适合作为入门级别的游戏开发案例。通过本项
目录
一、前言
随着鸿蒙操作系统的快速发展,越来越多的开发者开始关注鸿蒙平台的应用开发。Flutter作为一款优秀的跨平台UI框架,也在鸿蒙平台上得到了良好的支持。本文将介绍如何使用Flutter框架开发一款适合鸿蒙平台的井字棋小游戏,通过实际项目学习Flutter在鸿蒙平台上的开发流程和技术要点。
井字棋(Tic-Tac-Toe)是一款经典的双人对战游戏,规则简单易懂,非常适合作为入门级别的游戏开发案例。通过本项目,我们可以学习到Flutter的状态管理、UI设计、游戏逻辑实现以及如何适配鸿蒙OS设计风格等知识点。
二、效果展示


三、项目结构
核心文件
lib/main.dart:主应用入口,包含完整的游戏实现代码
pubspec.yaml:项目依赖配置文件
ohos/:鸿蒙平台相关代码目录
项目配置
✅ Flutter SDK:3.0+版本
✅ Dart语言:2.17+版本
✅ 鸿蒙OS:支持最新版本
四、核心代码实现
1. 鸿蒙风格主题配置
// 鸿蒙风格主题配置 - 严格遵循鸿蒙OS设计规范
final harmonyTheme = ThemeData(
// 鸿蒙OS核心色彩系统
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF007DFF), // 鸿蒙蓝 - 主色调
primary: const Color(0xFF007DFF),
secondary: const Color(0xFF34C759), // 鸿蒙绿 - 辅助色
background: const Color(0xFFF2F2F7), // 鸿蒙背景色
surface: Colors.white,
error: const Color(0xFFFF3B30), // 错误色
onPrimary: Colors.white,
onSecondary: Colors.white,
onBackground: const Color(0xFF000000),
onSurface: const Color(0xFF000000),
onError: Colors.white,
),
useMaterial3: true,
// 鸿蒙风格文本主题 - 严格遵循鸿蒙字体规范
textTheme: const TextTheme(
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
headlineMedium: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
headlineSmall: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
titleLarge: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.normal),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.normal),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
// 鸿蒙风格AppBar - 无阴影,居中标题
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF007DFF),
foregroundColor: Colors.white,
elevation: 0,
centerTitle: true,
),
// 鸿蒙风格Scaffold背景色
scaffoldBackgroundColor: Color(0xFFF2F2F7),
);
2. 游戏状态管理
/// 游戏状态枚举
enum GameState {
playing, // 游戏进行中
playerXWon, // X玩家获胜
playerOWon, // O玩家获胜
draw, // 平局
}
// 棋盘大小
static const int _boardSize = 3;
// 空状态,X玩家,O玩家
static const String _empty = '';
static const String _playerX = 'X';
static const String _playerO = 'O';
// 棋盘状态,二维数组表示
late List<List<String>> _board;
// 当前玩家
late String _currentPlayer;
// 游戏状态
late GameState _gameState;
// 获胜线路
late List<int> _winningLine;
// 游戏历史记录
late List<String> _gameHistory;
3. 游戏核心逻辑
游戏初始化
/// 初始化游戏
void _initializeGame() {
// 初始化空棋盘
_board = List.generate(
_boardSize,
(_) => List.generate(_boardSize, (_) => _empty),
);
// X玩家先手
_currentPlayer = _playerX;
// 游戏开始
_gameState = GameState.playing;
// 初始化获胜线路为[-1, -1, -1, -1],表示无获胜线路
_winningLine = [-1, -1, -1, -1];
// 清空游戏历史
_gameHistory = [];
}
点击事件处理
/// 处理玩家点击棋盘
void _handleTap(int row, int col) {
// 如果游戏已结束或该位置已被占用,不处理点击
if (_gameState != GameState.playing || _board[row][col] != _empty) {
return;
}
setState(() {
// 在点击位置放置当前玩家的棋子
_board[row][col] = _currentPlayer;
// 添加到游戏历史
_gameHistory.add('${_currentPlayer} 在 ($row, $col) 位置落子');
// 检查游戏状态
_checkGameState();
// 如果游戏未结束,切换玩家
if (_gameState == GameState.playing) {
_currentPlayer = _currentPlayer == _playerX ? _playerO : _playerX;
}
});
}
胜负判断
/// 检查游戏状态
void _checkGameState() {
// 检查所有行
for (int row = 0; row < _boardSize; row++) {
if (_board[row][0] != _empty &&
_board[row][0] == _board[row][1] &&
_board[row][1] == _board[row][2]) {
_gameState = _board[row][0] == _playerX ? GameState.playerXWon : GameState.playerOWon;
_winningLine = [row, 0, row, 2];
return;
}
}
// 检查所有列
for (int col = 0; col < _boardSize; col++) {
if (_board[0][col] != _empty &&
_board[0][col] == _board[1][col] &&
_board[1][col] == _board[2][col]) {
_gameState = _board[0][col] == _playerX ? GameState.playerXWon : GameState.playerOWon;
_winningLine = [0, col, 2, col];
return;
}
}
// 检查对角线(从左上到右下)
if (_board[0][0] != _empty &&
_board[0][0] == _board[1][1] &&
_board[1][1] == _board[2][2]) {
_gameState = _board[0][0] == _playerX ? GameState.playerXWon : GameState.playerOWon;
_winningLine = [0, 0, 2, 2];
return;
}
// 检查对角线(从右上到左下)
if (_board[0][2] != _empty &&
_board[0][2] == _board[1][1] &&
_board[1][1] == _board[2][0]) {
_gameState = _board[0][2] == _playerX ? GameState.playerXWon : GameState.playerOWon;
_winningLine = [0, 2, 2, 0];
return;
}
// 检查是否平局
bool isDraw = true;
for (int row = 0; row < _boardSize; row++) {
for (int col = 0; col < _boardSize; col++) {
if (_board[row][col] == _empty) {
isDraw = false;
break;
}
}
if (!isDraw) break;
}
if (isDraw) {
_gameState = GameState.draw;
_winningLine = [-1, -1, -1, -1];
}
}
4. 棋盘UI实现
/// 构建棋盘
Widget _buildBoard() {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: _boardSize,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
),
itemCount: _boardSize * _boardSize,
itemBuilder: (context, index) {
final row = index ~/ _boardSize;
final col = index % _boardSize;
return _buildCell(row, col);
},
);
}
/// 构建棋盘单元格
Widget _buildCell(int row, int col) {
final cellValue = _board[row][col];
final isSelected = cellValue != _empty;
final isWinningCell = _isWinningCell(row, col);
return GestureDetector(
onTap: () => _handleTap(row, col),
child: Container(
decoration: BoxDecoration(
color: isWinningCell ? Colors.yellow.withOpacity(0.3) : Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
border: Border.all(
color: isWinningCell ? Colors.yellow : const Color(0xFFE0E0E0),
width: isWinningCell ? 2.0 : 1.0,
),
),
child: Center(
child: AnimatedScale(
scale: isSelected ? 1.0 : 0.5,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
child: Text(
cellValue,
style: TextStyle(
fontSize: 48.0,
fontWeight: FontWeight.bold,
color: cellValue == _playerX ? Colors.red : Colors.blue,
),
),
),
),
),
);
}
五、遇到的问题
1. 状态管理问题
问题描述:在游戏逻辑实现中,初始尝试使用多个独立变量管理游戏状态,导致代码混乱且难以维护。
解决方案:改用枚举类型GameState统一管理游戏状态,使用二维数组表示棋盘,使代码结构更清晰,便于维护和扩展。
2. 获胜线路高亮问题
问题描述:如何高效地高亮显示获胜线路,同时不影响游戏性能。
解决方案:使用_winningLine数组存储获胜线路的起始和结束坐标,通过_isWinningCell方法判断每个单元格是否在获胜线路上,然后动态调整单元格样式。
3. 动画效果优化
问题描述:初始实现中,棋子显示缺乏动画效果,用户体验不佳。
解决方案:使用AnimatedScale组件为棋子添加缩放动画,使棋子显示更加流畅自然。
六、总结
本项目成功实现了一款基于Flutter框架和鸿蒙OS设计风格的井字棋小游戏。通过本项目,我们学习到了以下知识点:
- Flutter跨平台开发:如何使用Flutter框架开发跨平台应用,特别是针对鸿蒙平台的适配。
- 鸿蒙OS设计风格:如何在Flutter应用中实现鸿蒙OS的设计风格,包括色彩、字体、阴影等。
- 状态管理:如何使用Flutter的StatefulWidget进行复杂的状态管理,特别是游戏状态的管理。
- 游戏逻辑实现:如何实现完整的游戏逻辑,包括棋盘状态管理、玩家切换、胜负判断等。
- UI设计与动画:如何设计美观的UI界面,以及如何添加流畅的动画效果。
- 项目优化:如何优化项目结构,移除不必要的代码,提高项目的可维护性。
本项目虽然简单,但涵盖了Flutter开发的许多核心知识点,适合作为Flutter入门学习的案例。通过不断优化和扩展,我们可以将这款简单的井字棋游戏发展成为功能更丰富、体验更好的游戏应用,例如添加AI对手、多种游戏模式、游戏记录等功能。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)