Flutter for OpenHarmony 实战:食物生成算法与难度递增系统

文章目录
- [Flutter for OpenHarmony 实战:食物生成算法与难度递增系统](#Flutter for OpenHarmony 实战:食物生成算法与难度递增系统)
-
- 一、前言
- 二、随机食物生成
-
- [2.1 随机数获取方法](#2.1 随机数获取方法)
- [2.2 坐标范围控制](#2.2 坐标范围控制)
- 三、避免蛇身重叠算法
-
- [3.1 递归检测方案](#3.1 递归检测方案)
- [3.2 重叠判断逻辑](#3.2 重叠判断逻辑)
- [3.3 性能考虑](#3.3 性能考虑)
- 四、得分系统实现
-
- [4.1 得分规则设计](#4.1 得分规则设计)
- [4.2 UI实时更新机制](#4.2 UI实时更新机制)
- 五、难度递增机制
-
- [5.1 速度控制算法](#5.1 速度控制算法)
- [5.2 速度递减策略](#5.2 速度递减策略)
- [5.3 最快速度限制](#5.3 最快速度限制)
- 六、完整代码实现
- 七、扩展思考
- 八、总结
- 社区支持
一、前言
食物是贪吃蛇游戏的核心元素,驱动玩家不断移动。本文将详细讲解随机食物生成算法、避免蛇身重叠的递归检测、得分系统设计以及难度递增机制。

二、随机食物生成
2.1 随机数获取方法
Flutter中获取随机数:
dart
void _spawnFood() {
final random = DateTime.now().millisecondsSinceEpoch;
int x = random % gridWidth; // 0-29
int y = (random ~/ gridWidth) % gridHeight; // 0-19
food = Point(x, y);
}
算法解析:
DateTime.now().millisecondsSinceEpoch:获取当前时间戳(毫秒)% gridWidth:取模运算,结果范围0-29~/ gridWidth:整除,用于生成y坐标
示例计算:
dart
// 假设当前时间戳:1234567890
random = 1234567890
x = 1234567890 % 30 = 0
y = (1234567890 ~/ 30) % 20 = 41152263 % 20 = 3
food = Point(0, 3)
2.2 坐标范围控制
确保食物在有效范围内:
dart
int x = random % gridWidth; // 0 ≤ x ≤ 29
int y = (random ~/ gridWidth) % gridHeight; // 0 ≤ y ≤ 19
边界验证:
- 最小值:x=0, y=0(左上角)
- 最大值:x=29, y=19(右下角)
- 覆盖全部600个格子



三、避免蛇身重叠算法
3.1 递归检测方案
问题:随机生成的食物可能与蛇身重叠!
dart
void _spawnFood() {
final random = DateTime.now().millisecondsSinceEpoch;
int x = random % gridWidth;
int y = (random ~/ gridWidth) % gridHeight;
food = Point(x, y);
// 递归检测:如果食物在蛇身上,重新生成
for (var segment in snake) {
if (segment.x == food!.x && segment.y == food!.y) {
_spawnFood(); // 递归调用
return;
}
}
}
算法流程:
- 生成随机坐标
- 遍历蛇身,检查是否重叠
- 如果重叠,递归调用自身重新生成
- 如果不重叠,结束
3.2 重叠判断逻辑
dart
for (var segment in snake) {
if (segment.x == food!.x && segment.y == food!.y) {
_spawnFood();
return;
}
}
判断条件:
- segment.x == food.x:x坐标相同
- segment.y == food.y:y坐标相同
- 两个条件都满足,说明重叠
示例:
dart
// 蛇身
snake = [
Point(5, 10),
Point(4, 10),
Point(3, 10),
];
// 随机生成食物
food = Point(4, 10);
// 检测:
// (5,10) vs (4,10) → 不同
// (4,10) vs (4,10) → 相同!重叠
// 递归调用 _spawnFood()



3.3 性能考虑
递归深度问题:
- 最坏情况:蛇占满整个网格(600节)
- 随机生成可能多次重叠
- 递归深度理论上可能很大
实际情况:
- 蛇一般不会超过50节
- 重叠概率很低(蛇长30节时,重叠概率=30/600=5%)
- 递归深度通常1-2层
优化方案(可选):
dart
void _spawnFood() {
// 获取所有空闲位置
List<Point> emptySpots = [];
for (int x = 0; x < gridWidth; x++) {
for (int y = 0; y < gridHeight; y++) {
Point p = Point(x, y);
if (!snake.contains(p)) {
emptySpots.add(p);
}
}
}
// 从空闲位置随机选择
if (emptySpots.isNotEmpty) {
final random = Random();
food = emptySpots[random.nextInt(emptySpots.length)];
}
}
四、得分系统实现
4.1 得分规则设计
dart
if (newHead.x == food!.x && newHead.y == food!.y) {
score += 10; // 每个食物10分
_spawnFood();
}
得分规则:
- 每吃一个食物:+10分
- 显示在AppBar右上角
- 实时更新
UI显示:
dart
AppBar(
actions: [
Text(
'得分: $score',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
)
4.2 UI实时更新机制
dart
void _update() {
// ...
if (newHead.x == food!.x && newHead.y == food!.y) {
score += 10; // 更新得分
setState(() {}); // 触发UI重建
}
}
setState作用:
- 标记widget为dirty
- 调度帧重建
- build方法重新执行
- AppBar中的score文本更新
五、难度递增机制
5.1 速度控制算法
dart
int speed = 200; // 初始速度:200ms/次
void _update() {
if (newHead.x == food!.x && newHead.y == food!.y) {
score += 10;
// 速度递增
if (speed > 80) { // 最快80ms
speed -= 5; // 每次加速5ms
gameTimer?.cancel();
_startGame(); // 重建定时器
}
_spawnFood();
}
}
速度变化表:
| 得分 | 速度 | 频率 |
|---|---|---|
| 0 | 200ms | 5次/秒 |
| 10 | 195ms | 5.1次/秒 |
| 20 | 190ms | 5.3次/秒 |
| ... | ... | ... |
| 240 | 80ms | 12.5次/秒 |
5.2 速度递减策略
dart
if (speed > 80) {
speed -= 5; // 线性递减
gameTimer?.cancel();
_startGame();
}
策略特点:
- 线性递减:每吃一个食物,speed -= 5
- 下限保护:最快80ms(12.5次/秒)
- 递增次数:(200-80)/5 = 24次
- 最高得分:24 × 10 = 240分
5.3 最快速度限制
dart
if (speed > 80) { // 限制条件
speed -= 5;
}
为什么设置下限?
- 速度太快玩家无法反应
- 80ms ≈ 12.5次/秒,已经很快
- 保持游戏可玩性
曲线特征:
- 线性递减
- 起点:(0, 200)
- 终点:(240, 80)
- 240分后速度不再增加
六、完整代码实现
dart
class _GameHomePageState extends State<GameHomePage> {
int score = 0;
int speed = 200;
void _spawnFood() {
final random = DateTime.now().millisecondsSinceEpoch;
int x = random % gridWidth;
int y = (random ~/ gridWidth) % gridHeight;
food = Point(x, y);
for (var segment in snake) {
if (segment.x == food!.x && segment.y == food!.y) {
_spawnFood();
return;
}
}
}
void _update() {
if (nextDirection != null) {
direction = nextDirection!;
}
Point newHead = _getNewHead();
if (_checkCollision(newHead)) {
_gameOver();
return;
}
snake.insert(0, newHead);
if (newHead.x == food!.x && newHead.y == food!.y) {
// 吃到食物
score += 10;
// 速度递增
if (speed > 80) {
speed -= 5;
gameTimer?.cancel();
_startGame();
}
_spawnFood();
} else {
snake.removeLast();
}
setState(() {});
}
void _startGame() {
gameTimer?.cancel();
gameTimer = Timer.periodic(Duration(milliseconds: speed), (timer) {
if (!isPaused && !isGameOver) {
_update();
}
});
}
}
七、扩展思考
扩展1:不同食物分值
dart
class Food {
final Point position;
final int points; // 不同食物不同分值
final Color color;
}
Food _spawnFood() {
// 30%概率生成高分食物
if (Random().nextDouble() < 0.3) {
return Food(Point(x, y), 20, Colors.gold);
}
return Food(Point(x, y), 10, Colors.red);
}
扩展2:速度曲线调整
dart
// 非线性递增
if (speed > 80) {
int decrement = 5 + (score ~/ 50); // 随得分加速更快
speed = max(80, speed - decrement);
}
八、总结
本文讲解了食物生成与难度系统:
- 随机生成:基于时间戳的伪随机算法
- 避免重叠:递归检测确保食物不在蛇身上
- 得分系统:每食物10分,实时更新UI
- 难度递增:速度线性递增,最快80ms
下篇预告:《Flutter for OpenHarmony 实战:CustomPainter游戏画面渲染详解》
社区支持
欢迎加入开源 OpenHarmony 跨平台社区,获取更多技术支持和资源:
- 社区论坛 :开源 OpenHarmony 跨平台开发者社区
- 技术交流:参与社区讨论,分享开发经验
如果本文对您有帮助,欢迎点赞、收藏和评论。您的支持是我持续创作的动力!