连连看游戏应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图




1.1 应用简介
连连看是一款经典的消除类益智游戏,玩家需要在棋盘上找到两个相同的图案,并且它们之间可以用不超过两个拐点的路径连接起来,成功连接后即可消除。游戏以紫色为主色调,传递神秘、优雅的品牌形象。
应用支持多种水果图案,包含计时、计分、提示、洗牌等功能,通过精美的动画效果和流畅的交互体验,为玩家带来愉悦的游戏感受。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 游戏棋盘 | 8x6格子的游戏区域 | GridView |
| 路径检测 | 判断两个图案是否可连接 | 算法检测 |
| 连接动画 | 显示连接路径动画 | CustomPainter |
| 计时系统 | 倒计时游戏时间 | Timer |
| 计分系统 | 根据时间和步数计分 | 公式计算 |
| 提示功能 | 提示可消除的配对 | 遍历查找 |
| 洗牌功能 | 重新排列未消除的图案 | 随机打乱 |
1.3 游戏规则
| 规则名称 | 规则描述 |
|---|---|
| 配对消除 | 选择两个相同图案进行消除 |
| 路径限制 | 连接路径最多只能有两个拐点 |
| 时间限制 | 每关有180秒的时间限制 |
| 得分规则 | 基础分+时间奖励分 |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | setState | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.5 项目结构
lib/
└── main_link_game.dart
├── LinkGameApp # 应用入口
├── TileType # 图案类型模型
├── Tile # 格子数据模型
├── MainPage # 主页面(底部导航)
├── GamePage # 游戏页面
├── LevelsPage # 关卡选择页面
└── ProfilePage # 个人中心页面
二、系统架构
2.1 整体架构图
Data Layer
Business Layer
Presentation Layer
主页面
MainPage
游戏页面
关卡页面
个人中心
游戏棋盘
计分系统
计时系统
提示功能
洗牌功能
关卡列表
难度选择
游戏记录
排行榜
路径检测算法
连接动画
得分计算
Tile
格子模型
TileType
图案模型
2.2 类图设计
contains
manages
uses
LinkGameApp
+Widget build()
TileType
+int id
+String emoji
+Color color
Tile
+int row
+int col
+int typeId
+bool isMatched
+bool isSelected
MainPage
-int _currentIndex
+Widget build()
GamePage
-List<List<Tile>> _board
-Tile? _selectedTile
-int _score
-int _moves
-int _timeLeft
-bool _isPlaying
+void _initGame()
+void _onTileTap()
+List<Offset>? _findPath()
+void _useHint()
+void _shuffle()
2.3 游戏流程图
点击
否
是
否
是
否
是
否
是
超时
开始游戏
生成棋盘
显示图案
选择图案
标记选中
是否已选中其他图案?
等待选择第二个
图案是否相同?
切换选中状态
路径是否可连接?
显示连接路径
消除图案
是否全部消除?
游戏胜利
游戏失败
2.4 路径检测算法
是
否
是
否
是
否
开始检测
是否相邻?
直接连接
是否可一个拐点连接?
一个拐点路径
是否可两个拐点连接?
两个拐点路径
无法连接
返回路径
返回null
三、核心模块设计
3.1 数据模型设计
3.1.1 图案类型模型 (TileType)
dart
class TileType {
final int id; // 类型ID
final String emoji; // 表情符号
final Color color; // 背景颜色
}
3.1.2 格子模型 (Tile)
dart
class Tile {
final int row; // 行号
final int col; // 列号
int typeId; // 图案类型ID
bool isMatched; // 是否已消除
bool isSelected; // 是否被选中
}
3.1.3 图案类型列表
应用包含16种水果图案:
| ID | 图案 | 背景色 |
|---|---|---|
| 1 | 🍎 | 浅红色 |
| 2 | 🍊 | 浅橙色 |
| 3 | 🍋 | 浅黄色 |
| 4 | 🍇 | 浅紫色 |
| 5 | 🍓 | 粉红色 |
| 6 | 🍑 | 浅橙色 |
| 7 | 🥝 | 浅绿色 |
| 8 | 🍒 | 红色 |
| 9 | 🍌 | 黄色 |
| 10 | 🥭 | 橙色 |
| 11 | 🍍 | 浅黄色 |
| 12 | 🫐 | 浅蓝色 |
| 13 | 🍉 | 红色 |
| 14 | 🥥 | 浅棕色 |
| 15 | 🍈 | 浅绿色 |
| 16 | 🍐 | 浅绿色 |
3.2 路径检测算法
3.2.1 直接路径检测
dart
List<Offset>? _findDirectPath(Tile start, Tile end) {
// 检查是否在同一行或同一列
if (start.row == end.row) {
// 检查行路径是否畅通
for (int c = min(start.col, end.col) + 1; c < max(start.col, end.col); c++) {
if (!_isCellEmpty(start.row, c)) return null;
}
return [Offset(start.col, start.row), Offset(end.col, end.row)];
}
// 类似处理列路径...
}
3.2.2 一个拐点路径检测
dart
List<Offset>? _findOneCornerPath(Tile start, Tile end) {
// 尝试通过中间点连接
if (_isCellEmpty(start.row, end.col)) {
final corner = Tile(row: start.row, col: end.col);
final path1 = _findDirectPath(start, corner);
final path2 = _findDirectPath(corner, end);
if (path1 != null && path2 != null) {
return [Offset(start.col, start.row), Offset(end.col, start.row), Offset(end.col, end.row)];
}
}
// 尝试另一种拐点...
}
3.2.3 两个拐点路径检测
dart
List<Offset>? _findTwoCornerPath(Tile start, Tile end) {
// 遍历所有可能的中间列
for (int c = -1; c <= cols; c++) {
if (_isCellEmpty(start.row, c) || c == -1 || c == cols) {
// 检查路径是否畅通...
}
}
// 遍历所有可能的中间行...
}
3.3 得分计算
得分=基础分+时间奖励 得分 = 基础分 + 时间奖励 得分=基础分+时间奖励
基础分=10 基础分 = 10 基础分=10
时间奖励=⌊剩余时间10⌋ 时间奖励 = \lfloor \frac{剩余时间}{10} \rfloor 时间奖励=⌊10剩余时间⌋
四、UI设计规范
4.1 配色方案
应用采用紫色为主色调,传递神秘、优雅的品牌形象:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #673AB7 (Purple) | 导航、强调元素 |
| 渐变起始 | #673AB7 | 头部渐变 |
| 渐变结束 | #9575CD | 头部渐变 |
| 成功色 | #4CAF50 | 消除成功 |
| 警告色 | #FF9800 | 时间警告 |
| 背景色 | #F5F5F5 | 页面背景 |
4.2 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 20px | Medium | #000000 |
| 得分数字 | 24px | Bold | 主题色 |
| 时间数字 | 16px | Medium | #757575 |
| 图案表情 | 28px | Regular | - |
4.3 组件规范
4.3.1 游戏格子
┌─────────────────────┐
│ │
│ 🍎 │
│ │
│ [选中时显示边框] │
│ │
└─────────────────────┘
4.3.2 连接路径
┌─────────────────────────────────────────┐
│ │
│ 🍎 ──────────────┐ │
│ │ │
│ │ │
│ └────────── 🍎 │
│ │
└─────────────────────────────────────────┘
4.3.3 游戏信息栏
┌─────────────────────────────────────────┐
│ 得分: 150 步数: 12 时间: 120s │
└─────────────────────────────────────────┘
五、核心功能实现
5.1 棋盘生成实现
dart
List<List<Tile>> _generateBoard() {
final totalTiles = rows * cols;
final pairCount = totalTiles ~/ 2;
final typesNeeded = min(pairCount, tileTypes.length);
List<int> types = [];
for (int i = 0; i < pairCount; i++) {
final typeId = (i % typesNeeded) + 1;
types.add(typeId);
types.add(typeId); // 成对添加
}
types.shuffle(); // 随机打乱
// 创建棋盘...
}
5.2 路径查找实现
dart
List<Offset>? _findPath(Tile start, Tile end) {
if (start.typeId != end.typeId) return null;
if (start.isMatched || end.isMatched) return null;
// 尝试直接连接
final directPath = _findDirectPath(start, end);
if (directPath != null) return directPath;
// 尝试一个拐点连接
final oneCornerPath = _findOneCornerPath(start, end);
if (oneCornerPath != null) return oneCornerPath;
// 尝试两个拐点连接
final twoCornerPath = _findTwoCornerPath(start, end);
if (twoCornerPath != null) return twoCornerPath;
return null;
}
5.3 连接动画实现
dart
class PathPainter extends CustomPainter {
final List<Offset> path;
final Animation<double> animation;
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.green
..strokeWidth = 4
..style = PaintingStyle.stroke;
final pathToDraw = Path();
for (int i = 0; i < path.length - 1; i++) {
final start = path[i];
final end = path[i + 1];
pathToDraw.moveTo(start.dx, start.dy);
pathToDraw.lineTo(end.dx, end.dy);
}
canvas.drawPath(pathToDraw, paint);
}
}
5.4 提示功能实现
dart
void _useHint() {
for (int r1 = 0; r1 < rows; r1++) {
for (int c1 = 0; c1 < cols; c1++) {
if (_board[r1][c1].isMatched) continue;
for (int r2 = 0; r2 < rows; r2++) {
for (int c2 = 0; c2 < cols; c2++) {
if (r1 == r2 && c1 == c2) continue;
if (_board[r2][c2].isMatched) continue;
if (_board[r1][c1].typeId != _board[r2][c2].typeId) continue;
final path = _findPath(_board[r1][c1], _board[r2][c2]);
if (path != null) {
// 高亮显示这对图案
return;
}
}
}
}
}
// 没有可消除的配对
}
5.5 洗牌功能实现
dart
void _shuffle() {
List<Tile> unmatchedTiles = [];
for (var row in _board) {
for (var tile in row) {
if (!tile.isMatched) {
unmatchedTiles.add(tile);
}
}
}
List<int> types = unmatchedTiles.map((t) => t.typeId).toList();
types.shuffle(); // 随机打乱类型
for (int i = 0; i < unmatchedTiles.length; i++) {
unmatchedTiles[i].typeId = types[i];
}
}
六、交互设计
6.1 图案选择流程
动画 状态 棋盘 用户 动画 状态 棋盘 用户 alt [图案相同] [图案不同] alt [无选中图案] [已有选中图案] 点击图案 检查当前选中状态 标记为选中 检查图案是否相同 显示连接路径 消除图案 更新棋盘 切换选中状态
6.2 游戏计时流程
点击开始
倒计时
点击暂停
点击继续
全部消除
时间耗尽
准备开始
游戏中
暂停
胜利
失败
6.3 关卡进度流程
胜利
是
否
失败
是
否
开始关卡
显示目标
游戏进行中
是否完成?
计算得分
显示结果
是否继续?
进入下一关
返回关卡列表
显示失败
是否重试?
七、扩展功能规划
7.1 后续版本规划
2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 基础游戏 路径检测 动画效果 计分系统 多种图案 关卡系统 音效系统 多人对战 排行榜 成就系统 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 连连看游戏开发计划
7.2 功能扩展建议
7.2.1 多人对战模式
增强游戏趣味:
- 实时对战
- 轮流操作
- 道具干扰
7.2.2 关卡编辑器
自定义关卡:
- 自定义图案
- 自定义布局
- 分享关卡
7.2.3 成就系统
增加游戏粘性:
- 连胜成就
- 速度成就
- 收集成就
八、注意事项
8.1 开发注意事项
-
路径检测:确保路径检测算法正确处理边界情况
-
动画流畅:连接动画需要流畅不卡顿
-
状态同步:选中状态和消除状态需要及时更新
-
性能优化:大量图案时注意渲染性能
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 路径检测错误 | 边界条件处理不当 | 检查边界判断逻辑 |
| 动画卡顿 | 重绘过于频繁 | 使用RepaintBoundary |
| 无法消除 | 洗牌后无可消除配对 | 检测并重新洗牌 |
| 内存泄漏 | 动画未释放 | 正确释放AnimationController |
8.3 使用提示
🎮 连连看游戏技巧 🎮
眼疾手快:快速找到相同图案。
规划路径:注意路径是否有阻挡。
善用提示:卡住时使用提示功能。
合理洗牌:图案太乱时及时洗牌。
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
9.2 运行命令
bash
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_link_game.dart --web-port 8102
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_link_game.dart
# 运行到Windows
flutter run -d windows -t lib/main_link_game.dart
# 代码分析
flutter analyze lib/main_link_game.dart
十、总结
连连看游戏通过经典的消除玩法,为玩家提供了一个休闲益智的娱乐体验。游戏支持16种水果图案,8x6的游戏棋盘,玩家需要在限定时间内消除所有图案。
核心功能涵盖游戏棋盘、路径检测、连接动画、计时计分、提示洗牌五大模块。游戏棋盘随机生成成对的图案;路径检测算法支持直连、一个拐点、两个拐点三种连接方式;连接动画通过CustomPainter绘制路径;计时计分系统增加游戏紧张感;提示和洗牌功能帮助玩家突破困境。
游戏采用Material Design 3设计规范,以紫色为主色调,界面优雅简洁。通过本游戏,希望能够为玩家带来愉悦的休闲时光。
经典连连看,休闲益智