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

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

文章目录

一、前言

食物是贪吃蛇游戏的核心元素,驱动玩家不断移动。本文将详细讲解随机食物生成算法、避免蛇身重叠的递归检测、得分系统设计以及难度递增机制。

二、随机食物生成

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;
    }
  }
}

算法流程:

  1. 生成随机坐标
  2. 遍历蛇身,检查是否重叠
  3. 如果重叠,递归调用自身重新生成
  4. 如果不重叠,结束

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);
}

八、总结

本文讲解了食物生成与难度系统:

  1. 随机生成:基于时间戳的伪随机算法
  2. 避免重叠:递归检测确保食物不在蛇身上
  3. 得分系统:每食物10分,实时更新UI
  4. 难度递增:速度线性递增,最快80ms

下篇预告:《Flutter for OpenHarmony 实战:CustomPainter游戏画面渲染详解》

社区支持

欢迎加入开源 OpenHarmony 跨平台社区,获取更多技术支持和资源:

如果本文对您有帮助,欢迎点赞、收藏和评论。您的支持是我持续创作的动力!

相关推荐
2501_9219308316 分钟前
基础入门 Flutter for OpenHarmony:SearchAnchor 搜索锚点组件详解
flutter
早點睡39038 分钟前
基础入门 Flutter for OpenHarmony:ReorderableListView 可排序列表详解
flutter
blackicexs1 小时前
第五周第二天
算法
不吃粑粑-1 小时前
FHQ Treap模版
数据结构·算法
追随者永远是胜利者1 小时前
(LeetCode-Hot100)22. 括号生成
java·算法·leetcode·职场和发展·go
CHANG_THE_WORLD1 小时前
多维数组传参为什么使用列指针?—— 深度解析
数据结构·算法
追随者永远是胜利者2 小时前
(LeetCode-Hot100)32. 最长有效括号
java·算法·leetcode·职场和发展·go
lifallen2 小时前
CDQ 分治 (CDQ Divide and Conquer)
java·数据结构·算法
追随者永远是胜利者2 小时前
(LeetCode-Hot100)31. 下一个排列
java·算法·leetcode·职场和发展·go
早點睡3902 小时前
基础入门 Flutter for OpenHarmony:DataTable 数据表格组件详解
flutter