当前位置: 首页 > news >正文

Flutter for OpenHarmony 实战:碰撞检测算法与游戏结束处理

Flutter for OpenHarmony 实战:碰撞检测算法与游戏结束处理

文章目录

  • Flutter for OpenHarmony 实战:碰撞检测算法与游戏结束处理
    • 一、前言
    • 二、碰撞检测概述
      • 2.1 墙壁碰撞
      • 2.2 自身碰撞
      • 2.3 检测时机
    • 三、墙壁碰撞检测
      • 3.1 边界判断算法
      • 3.2 坐标越界示例
      • 3.3 代码实现
    • 四、自身碰撞检测
      • 4.1 蛇身遍历算法
      • 4.2 头部与身体比较
      • 4.3 时间复杂度分析
    • 五、碰撞响应机制
      • 5.1 游戏结束状态设置
      • 5.2 定时器清理流程
      • 5.3 UI状态更新
    • 六、完整代码实现
    • 七、测试用例
    • 八、总结
    • 社区支持

一、前言

碰撞检测是游戏开发中的核心机制。在贪吃蛇游戏中,需要检测两种碰撞:撞墙(边界碰撞)和撞自己(自身碰撞)。本文将详细讲解这两种碰撞的检测算法、游戏结束处理流程以及状态管理。

二、碰撞检测概述

贪吃蛇游戏中需要检测的碰撞类型:

2.1 墙壁碰撞

  • 蛇头超出网格边界
  • x坐标 < 0 或 x ≥ 30
  • y坐标 < 0 或 y ≥ 20

2.2 自身碰撞

  • 蛇头与蛇身任意一节坐标重合
  • 不包括蛇头本身(索引0)

2.3 检测时机

每次蛇移动后,在插入新头部之前检测:

void_update(){PointnewHead=_getNewHead();// 计算新头部位置if(_checkCollision(newHead)){// 碰撞检测_gameOver();return;}snake.insert(0,newHead);// 无碰撞才插入}

三、墙壁碰撞检测

3.1 边界判断算法

bool_checkCollision(Pointpoint){// 检查墙壁碰撞if(point.x<0||point.x>=gridWidth||point.y<0||point.y>=gridHeight){returntrue;}// 检查自身碰撞(稍后讲解)// ...returnfalse;}

判断条件分析:

条件含义示例
point.x < 0超出左边界x=-1
point.x >= gridWidth超出右边界x=30
point.y < 0超出上边界y=-1
point.y >= gridHeight超出下边界y=20

为什么使用>=而不是>?

  • 有效坐标范围:0到gridWidth-1(即0到29)
  • gridWidth=30时,x=30已经超出边界
  • 所以判断条件是 x >= 30

3.2 坐标越界示例

// 示例1:蛇头在右边缘,向右移动Pointhead=Point(29,10);// 最右边direction=Direction.right;PointnewHead=Point(30,10);// 越界!_checkCollision(newHead);// 返回true// 示例2:蛇头在上边缘,向上移动Pointhead=Point(15,0);// 最上边direction=Direction.up;PointnewHead=Point(15,-1);// 越界!_checkCollision(newHead);// 返回true

3.3 代码实现

完整的墙壁碰撞检测:

bool_checkCollision(Pointpoint){// 墙壁碰撞检测if(point.x<0||point.x>=gridWidth||point.y<0||point.y>=gridHeight){returntrue;}// 自身碰撞检测for(varsegmentinsnake){if(segment.x==point.x&&segment.y==point.y){returntrue;}}returnfalse;}

四、自身碰撞检测

4.1 蛇身遍历算法

// 自身碰撞检测for(varsegmentinsnake){if(segment.x==point.x&&segment.y==segment.y){returntrue;// 发现碰撞}}

算法说明:

  1. 遍历snake列表中的每一节
  2. 将新头部坐标与每节坐标比较
  3. 如果x和y都相等,说明碰撞
  4. 返回true表示碰撞

4.2 头部与身体比较

重要:蛇头移动到的新位置,可能与蛇身的任意一节重合。

// 示例:蛇身坐标snake=[Point(5,10),// 索引0:当前头部Point(4,10),// 索引1:第二节Point(3,10),// 索引2:第三节];// 蛇向右移动,新头部PointnewHead=Point(6,10);// 检测:newHead与snake[0/1/2]比较// (6,10) vs (5,10) → 不同// (6,10) vs (4,10) → 不同// (6,10) vs (3,10) → 不同// 结果:无碰撞

碰撞示例:

// 蛇绕成一圈snake=[Point(5,10),Point(5,11),Point(5,12),Point(6,12),Point(7,12),];// 蛇头向上移动PointnewHead=Point(5,9);// 然后向右、向下移动...PointnewHead=Point(7,11);// 最终撞到自己的身体:(7,11) 与 (7,12) 相邻但y不同

4.3 时间复杂度分析

for(varsegmentinsnake){// O(n)if(segment.x==point.x&&segment.y==segment.y){returntrue;}}

时间复杂度:O(n)

  • n = snake.length(蛇的长度)
  • 最坏情况:遍历整个蛇身
  • 最好情况:第一节就碰撞(不太可能,因为蛇头不会撞到当前头部位置)

优化思路:

  • 蛇较短时(<100节),O(n)可接受
  • 蛇很长时,可以用HashSet存储身体坐标,O(1)查询
  • 但贪吃蛇游戏中蛇一般不会太长,O(n)足够

五、碰撞响应机制

5.1 游戏结束状态设置

void_gameOver(){isGameOver=true;gameTimer?.cancel();setState((){});}

状态变化:

  • isGameOver:false → true
  • 停止定时器
  • 更新UI显示游戏结束信息

5.2 定时器清理流程

void_gameOver(){isGameOver=true;// 标记游戏结束gameTimer?.cancel();// 取消定时器setState((){});// 触发UI更新}

为什么必须取消定时器?

  • 定时器会持续触发_update()
  • 如果不取消,会不断检测碰撞
  • 导致_gameOver()被重复调用
  • 浪费CPU资源

定时器清理时机:

  1. 游戏结束时:gameTimer?.cancel();
  2. 速度变化时:先cancel再重新创建
  3. 组件销毁时:dispose中cancel

5.3 UI状态更新

@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:Column(children:[Expanded(child:CustomPaint(painter:GamePainter(...),),),// 游戏结束时显示if(isGameOver)Container(child:Column(children:[Text('游戏结束!'),Text('最终得分:$score'),ElevatedButton(onPressed:()=>_initGame(),child:Text('重新开始'),),],),),],),);}

UI变化:

  • 游戏区域:定格在最后状态
  • 游戏结束面板:从隐藏变为显示
  • 控制按钮:隐藏(isGameOver为true时不显示)

六、完整代码实现

class_GameHomePageStateextendsState<GameHomePage>{// ...bool_checkCollision(Pointpoint){// 墙壁碰撞检测if(point.x<0||point.x>=gridWidth||point.y<0||point.y>=gridHeight){returntrue;}// 自身碰撞检测for(varsegmentinsnake){if(segment.x==point.x&&segment.y==point.y){returntrue;}}returnfalse;}void_gameOver(){isGameOver=true;gameTimer?.cancel();setState((){});}void_update(){if(nextDirection!=null){direction=nextDirection!;}PointnewHead=_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((){});}}

七、测试用例

测试1:墙壁碰撞

// 边界测试test('右边界碰撞',(){snake=[Point(29,10)];direction=Direction.right;PointnewHead=Point(30,10);expect(_checkCollision(newHead),true);});test('上边界碰撞',(){snake=[Point(15,0)];direction=Direction.up;PointnewHead=Point(15,-1);expect(_checkCollision(newHead),true);});

测试2:自身碰撞

test('撞到身体',(){snake=[Point(5,10),Point(4,10),Point(3,10),];// 蛇头移动到(3,10),与第三节重合PointnewHead=Point(3,10);expect(_checkCollision(newHead),true);});

八、总结

本文讲解了碰撞检测算法:

  1. 墙壁碰撞:检测坐标是否超出0-29和0-19范围
  2. 自身碰撞:遍历蛇身,比较坐标
  3. 游戏结束:设置标志、取消定时器、更新UI
  4. 时间复杂度:O(n),n为蛇身长度

关键要点:

  • 碰撞检测在移动前执行,防止无效移动
  • 定时器必须清理,避免资源浪费
  • 使用isGameOver标志控制UI状态

下篇预告:《Flutter for OpenHarmony 实战:食物生成算法与难度递增系统》

社区支持

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

  • 社区论坛:开源 OpenHarmony 跨平台开发者社区
  • 技术交流:参与社区讨论,分享开发经验

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

http://www.jsqmd.com/news/304427/

相关文章:

  • 2026年旧变压器回收厂家推荐:铜陵市泰源物资回收有限公司,废旧/干式/厢式变压器全品类回收
  • 基于Matlab的双边滤波去噪:图像的美颜魔法
  • 数据安全与合规:大数据治理的关键挑战与解决方案
  • 质量管理体系是什么,包括哪些内容?
  • Flutter for OpenHarmony 实战:贪吃蛇蛇的移动逻辑详解
  • 完整教程:Node.js 编程实战:自定义模块与包发布全流程解析
  • 强烈安利!8个AI论文网站测评:本科生毕业论文全攻略
  • 微信小程序开发一般多少钱?10年程序员给你讲透
  • Flutter for OpenHarmony 实战:贪吃蛇游戏核心架构设计
  • P10137 [USACO24JAN] Walking in Manhattan G
  • 基于S7-300 PLC和组态王的恒压供水系统搭建与实现
  • 基于Tent映射的混合灰狼优化改进算法:Matlab代码复现与解析
  • 自适应巡航 Carsim + Simulink 联合仿真:两车固定间距的奇妙之旅
  • 无人驾驶车辆高速MPC例子复现:从理论到实践
  • 基于TensorRT、YOLOv5和QT构建智能监控平台
  • 麻雀算法优化 XGBoost 实现拟合预测建模
  • 基于哈里斯鹰算法HHO-SEIR的传染病模型参数优化附Matlab代码
  • 【软考每日一练020】深入解析事务(Transaction)与ACID特性的工程实现
  • AI应用架构师的人机协作新范式流程设计最佳实践的技术支撑
  • 方波高频注入技术及其在代码实现中的应用
  • 导师推荐!专科生必看9款AI论文软件测评,开题报告神器TOP9
  • APP 外包开发公司怎么选?2026 年优质软件开发服务商分析与测评
  • 西门子PLC1200在制药厂生物发酵系统中的应用实例
  • 树莓派推出新款品牌USB闪存盘承诺高速性能表现
  • 使用安装包快速体验 TDengine TSDB
  • 为什么大容量硬盘挂载失败,而小优盘却能直接使用?——Linux 挂载文件系统问题解析
  • 1月26号
  • 2026.1.26
  • Java 队列接口
  • vue2与vue3的区别