news 2026/4/18 5:34:35

Flutter for OpenHarmony 实战:打地鼠游戏完整开发指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter for OpenHarmony 实战:打地鼠游戏完整开发指南

欢迎加入开源鸿蒙跨平台社区:开源鸿蒙跨平台开发者社区

Flutter for OpenHarmony 实战:打地鼠游戏完整开发指南

文章目录

  • Flutter for OpenHarmony 实战:打地鼠游戏完整开发指南
    • 摘要
    • 一、项目背景与功能概述
      • 1.1 打地鼠游戏介绍
      • 1.2 应用功能规划
      • 1.3 游戏配置
    • 二、数据模型设计
      • 2.1 游戏配置
      • 2.2 游戏初始化
    • 三、游戏循环实现
      • 3.1 开始游戏
      • 3.2 结束游戏
    • 四、地鼠生成算法
      • 4.1 随机生成地鼠
      • 4.2 难度调整
    • 五、点击检测实现
      • 5.1 打地鼠逻辑
      • 5.2 防止重复点击
    • 六、UI界面实现
      • 6.1 游戏网格
      • 6.2 地洞组件
      • 6.3 游戏信息面板
    • 七、资源管理
      • 7.1 定时器销毁
      • 7.2 游戏重置
    • 八、总结

摘要

打地鼠(Whack-a-Mole)是一款经典的街机休闲游戏,玩家需要在有限时间内尽可能多地点击从地洞中冒出的地鼠来得分。本文将详细介绍如何使用Flutter for OpenHarmony框架开发一款功能完整的打地鼠游戏。文章涵盖了定时器管理、随机生成算法、点击检测、倒计时实现等核心技术点。通过本文学习,读者将掌握Flutter在反应类游戏开发中的完整流程,了解多定时器协调和状态管理的应用。


一、项目背景与功能概述

1.1 打地鼠游戏介绍

打地鼠是一款考验反应速度的经典街机游戏:

  • 目标:在限定时间内打中尽可能多的地鼠
  • 规则
    1. 地鼠随机从地洞中冒出
    2. 点击地鼠得分
    3. 每个地鼠只能打一次
    4. 时间结束后游戏结束

1.2 应用功能规划

功能模块具体功能
游戏网格3×3地洞布局
地鼠生成随机位置、随机数量
点击检测判断是否打中地鼠
倒计时30秒游戏时间
分数计算每打中一只得10分
最高分记录保存历史最高分
游戏控制开始、结束、重新开始
视觉反馈打中特效显示

1.3 游戏配置

参数说明
网格大小3×3地洞数量
游戏时长30秒倒计时
地鼠显示时间800ms地鼠停留时间
同时出现数量1-2只随机变化
每只地鼠得分10分数增量

二、数据模型设计

2.1 游戏配置

class_GamePageStateextendsState<GamePage>{// 游戏配置staticconstint _gridRows=3;staticconstint _gridCols=3;staticconstint _gameDuration=30;// 游戏时长(秒)staticconstint _moleShowTime=800;// 地鼠显示时间(毫秒)// 游戏状态List<List<bool>>_moles=[];// 地鼠位置List<List<bool?>>_hitStatus=[];// 打击状态int _score=0;// 当前分数int _bestScore=0;// 最高分int _timeLeft=_gameDuration;// 剩余时间bool _gameRunning=false;// 游戏运行标志bool _gameOver=false;// 游戏结束标志Timer?_gameTimer;// 游戏倒计时时钟Timer?_moleTimer;// 地鼠生成时钟finalRandom_random=Random();}

2.2 游戏初始化

void_initGame(){_gameTimer?.cancel();_moleTimer?.cancel();_moles=List.generate(_gridRows,(_)=>List.filled(_gridCols,false));_hitStatus=List.generate(_gridRows,(_)=>List.filled(_gridCols,null));_score=0;_timeLeft=_gameDuration;_gameRunning=false;_gameOver=false;setState((){});}

三、游戏循环实现

3.1 开始游戏

void_startGame(){_initGame();_gameRunning=true;// 启动倒计时_gameTimer=Timer.periodic(constDuration(seconds:1),(timer){setState((){_timeLeft--;if(_timeLeft<=0){_endGame();}});});// 启动地鼠生成_spawnMole();_moleTimer=Timer.periodic(Duration(milliseconds:_moleShowTime),(timer){if(_gameRunning){_spawnMole();}});setState((){});}

双定时器设计

  1. _gameTimer:每秒触发一次,处理倒计时
  2. _moleTimer:每800ms触发一次,生成新的地鼠

3.2 结束游戏

void_endGame(){_gameTimer?.cancel();_moleTimer?.cancel();_gameRunning=false;_gameOver=true;if(_score>_bestScore){_bestScore=_score;}_showGameOverDialog();}

四、地鼠生成算法

4.1 随机生成地鼠

void_spawnMole(){setState((){// 清除之前的地鼠for(int r=0;r<_gridRows;r++){for(int c=0;c<_gridCols;c++){_moles[r][c]=false;}}// 收集所有位置finalpositions=<Point>[];for(int r=0;r<_gridRows;r++){for(int c=0;c<_gridCols;c++){positions.add(Point(r,c));}}positions.shuffle(_random);// 随机选择1-2个位置显示地鼠finalmoleCount=_random.nextInt(2)+1;for(int i=0;i<moleCount&&i<positions.length;i++){finalpos=positions[i];_moles[pos.x.toInt()][pos.y.toInt()]=true;_hitStatus[pos.x.toInt()][pos.y.toInt()]=null;}});}

算法特点

  • 使用洗牌算法随机排列位置
  • 随机选择1-2个位置显示地鼠
  • 清除旧地鼠状态避免重复

4.2 难度调整

可以通过调整参数来改变游戏难度:

// 简单模式:地鼠显示时间长staticconstint _moleShowTime=1200;// 困难模式:地鼠显示时间短staticconstint _moleShowTime=500;// 同时出现更多地鼠finalmoleCount=_random.nextInt(3)+1;// 1-3只

五、点击检测实现

5.1 打地鼠逻辑

void_whackMole(int row,int col){if(!_gameRunning)return;if(!_moles[row][col])return;if(_hitStatus[row][col]==true)return;// 已经打过了setState((){_hitStatus[row][col]=true;_score+=10;// 立即隐藏地鼠_moles[row][col]=false;});}

检测条件

  1. 游戏正在运行
  2. 该位置有地鼠
  3. 该地鼠还未被打过

5.2 防止重复点击

使用_hitStatus数组记录每个位置的打击状态:

  • null:未显示地鼠
  • false:地鼠显示但未被打
  • true:地鼠已被打中

六、UI界面实现

6.1 游戏网格

Widget_buildGameGrid(){returnContainer(padding:constEdgeInsets.all(16),decoration:BoxDecoration(color:Colors.green.shade200,borderRadius:BorderRadius.circular(16),border:Border.all(color:Colors.brown.shade700,width:4),),child:GridView.builder(primary:true,padding:EdgeInsets.zero,gridDelegate:constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:_gridCols,crossAxisSpacing:16,mainAxisSpacing:16,childAspectRatio:1.0,),itemCount:_gridRows*_gridCols,itemBuilder:(context,index){finalrow=index~/_gridCols;finalcol=index%_gridCols;return_buildHole(row,col);},),);}

6.2 地洞组件

Widget_buildHole(int row,int col){finalhasMole=_moles[row][col];finalisHit=_hitStatus[row][col]==true;returnGestureDetector(onTap:()=>_whackMole(row,col),child:Container(decoration:BoxDecoration(color:Colors.brown.shade700,borderRadius:BorderRadius.circular(16),border:Border.all(color:Colors.brown.shade900,width:3,),),child:Stack(children:[// 地洞背景Center(child:Container(width:80,height:40,decoration:BoxDecoration(color:Colors.brown.shade900,borderRadius:BorderRadius.circular(40),),),),// 地鼠if(hasMole&&!isHit)Positioned(bottom:20,left:0,right:0,child:Center(child:Container(width:60,height:60,decoration:BoxDecoration(color:Colors.brown,shape:BoxShape.circle,border:Border.all(color:Colors.brown.shade700,width:3,),),child:constColumn(mainAxisAlignment:MainAxisAlignment.center,children:[Icon(Icons.pets,size:24,color:Colors.white),SizedBox(height:2),Row(mainAxisAlignment:MainAxisAlignment.center,children:[Icon(Icons.visibility,size:8,color:Colors.black),SizedBox(width:8),Icon(Icons.visibility,size:8,color:Colors.black),],),Icon(Icons.sentiment_satisfied,size:16,color:Colors.white),],),),),),// 打击效果if(isHit)Positioned(bottom:20,left:0,right:0,child:Center(child:Container(width:60,height:60,decoration:BoxDecoration(color:Colors.amber,shape:BoxShape.circle,border:Border.all(color:Colors.orange,width:3),),child:constIcon(Icons.star,size:40,color:Colors.white,),),),),],),),);}

6.3 游戏信息面板

Container(padding:constEdgeInsets.all(16),color:Colors.brown.shade100,child:Row(mainAxisAlignment:MainAxisAlignment.spaceAround,children:[Column(children:[constIcon(Icons.score,size:20),constSizedBox(height:4),Text('得分:$_score',style:constTextStyle(fontSize:20,fontWeight:FontWeight.bold,),),],),Column(children:[constIcon(Icons.timer,size:20),constSizedBox(height:4),Text('时间:$_timeLeft秒',style:TextStyle(fontSize:20,fontWeight:FontWeight.bold,color:_timeLeft<=10?Colors.red:Colors.black,),),],),],),)

七、资源管理

7.1 定时器销毁

@overridevoiddispose(){_gameTimer?.cancel();_moleTimer?.cancel();super.dispose();}

重要:在dispose方法中取消所有定时器,防止内存泄漏。

7.2 游戏重置

void_initGame(){_gameTimer?.cancel();// 先取消旧定时器_moleTimer?.cancel();// ... 初始化逻辑 ...setState((){});}

八、总结

本文详细介绍了使用Flutter for OpenHarthon开发打地鼠游戏的完整过程,涵盖了以下核心技术点:

  1. 数据模型:地鼠位置、打击状态、游戏配置
  2. 游戏循环:双定时器设计、倒计时实现
  3. 地鼠生成:随机算法、难度调整
  4. 点击检测:状态判断、防止重复
  5. UI实现:网格布局、堆叠组件、动画效果
  6. 资源管理:定时器销毁、内存管理

这个项目展示了Flutter在反应类游戏开发中的完整流程,特别是多定时器协调和状态管理的应用。


欢迎加入开源鸿蒙跨平台社区: 开源鸿蒙跨平台开发者社区

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/30 21:33:05

使用arthas生成火焰图

下载arthas https://arthas.aliyun.com/ #下载包 curl -O https://arthas.aliyun.com/arthas-boot.jar 挂载目录 #添加ksb-recycle挂载本地/opt/bin目录 vim docker-compose-app.yml 重启ksb-recycle服务 #重启ksb-recycle服务 docker-compose -f docker-compose-app.yml …

作者头像 李华
网站建设 2026/4/16 18:32:12

AI写教材神器来袭!低查重特性,一键生成专业教材!

编写教材的困境与AI的解决方案 在编写教材的过程中&#xff0c;总是能深刻感受到“慢节奏”的各类坑。尽管框架和参考资料已准备好&#xff0c;却总是在内容创作上遇到阻碍——某句话反复推敲半个小时&#xff0c;仍觉得表达不够准确&#xff1b;章节之间的衔接&#xff0c;总…

作者头像 李华
网站建设 2026/4/15 11:20:15

光伏电站气象监测仪 太阳能光伏气象站

太阳能光伏气象站 核心作用是“精准捕捉气象数据&#xff0c;为光伏运维、发电量预测提供可靠支撑”&#xff0c;直击光伏运维3大核心数据痛点&#xff01;首先&#xff0c;解决数据不准的问题&#xff0c;实测这款光伏气象站精度稳得不像话&#xff0c;各项监测数据误差严格…

作者头像 李华
网站建设 2026/4/15 16:59:37

腾讯云高性价比GPU算力,开启AI时代

腾讯云高性价比GPU算力概述腾讯云作为国内领先的云计算服务商&#xff0c;提供多样化的GPU算力解决方案&#xff0c;覆盖从入门级训练到高性能计算的场景。其GPU实例基于NVIDIA Tesla系列显卡&#xff08;如T4、V100、A100等&#xff09;&#xff0c;支持CUDA、TensorFlow、PyT…

作者头像 李华