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

水果翻牌游戏新特性接入

效果

一、整体架构

Index.ets ├── @ObservedV2 CardItem // 数据模型(细粒度响应) ├── @ComponentV2 CardView // 单张卡片子组件 └── @Entry @ComponentV2 Index // 主页面(状态持有者)

所有组件均使用状态管理 V2@ComponentV2+@Local+@ObservedV2+@Trace),没有引入任何 V1 装饰器。


二、实现流程

1. 定义数据模型 CardItem └── @ObservedV2 + @Trace 实现属性级响应 2. 编写初始化函数 ├── createCards() 生成 16 张牌(8 对 emoji) └── shuffle() Fisher-Yates 洗牌 3. 封装 CardView 子组件 ├── @Param card 接收卡片数据 ├── @Event onFlip 向父层上报翻牌事件 └── Stack 切换正/背面显示 4. 主页面 Index 状态管理 ├── @Local cards[] 当前牌组 ├── @Local moves 翻牌次数 ├── @Local matchedCount 配对数 ├── @Local firstIndex 第一张翻开的索引 ├── @Local isChecking 防抖锁(两张比较期间锁定) └── @Computed isGameOver 派生:是否全部配对 5. handleFlip() 核心翻牌逻辑 ├── 翻第一张 → 记录 firstIndex ├── 翻第二张 → 对比 emoji │ ├── 匹配 → isMatched = true,matchedCount++ │ └── 不匹配 → setTimeout 900ms 翻回 └── isChecking 防止比较期间继续翻牌 6. resetGame() 重置所有状态

三、关键代码讲解

3.1 数据模型 —@ObservedV2 + @Trace
@ObservedV2classCardItem{publicid:number=0;@Tracepublicemoji:string='';@TracepublicisFlipped:boolean=false;@TracepublicisMatched:boolean=false;}

为什么用@ObservedV2 + @Trace

V2 中@Trace实现属性级精确更新:只有被修改的属性会触发对应 UI 刷新,避免整个卡片列表重新渲染。若用 V1 的@Observed,嵌套属性变更无法可靠触发更新。


3.2 初始化牌组 — 显式 for 循环(规避 ArkTS 泛型推断限制)
functioncreateCards():CardItem[]{constcards:CardItem[]=[];for(leti=0;i<FRUIT_EMOJIS.length;i++){cards.push(newCardItem(i*2,FRUIT_EMOJIS[i]));cards.push(newCardItem(i*2+1,FRUIT_EMOJIS[i]));}returnshuffle(cards);}

3.3 子组件通信 —@Param + @Event
@ComponentV2struct CardView{@Paramcard:CardItem=newCardItem(0,'');// 父 → 子,单向@EventonFlip:()=>void=()=>{};// 子 → 父,事件上报build(){Stack(){/* ... */}.onClick(()=>{if(!this.card.isFlipped&&!this.card.isMatched){this.onFlip();// 通知父层处理翻牌}})}}

@Param替代 V1 的@Prop@Event替代回调 prop 模式,语义更清晰。


3.4 核心翻牌逻辑 —handleFlip()
privatehandleFlip(index:number):void{if(this.isChecking){return;}constcard=this.cards[index];if(card.isFlipped||card.isMatched){return;}card.isFlipped=true;if(this.firstIndex===-1){// 翻第一张this.firstIndex=index;}else{// 翻第二张,做比较this.moves+=1;this.isChecking=true;constfirst=this.cards[this.firstIndex];constsecond=this.cards[index];if(first.emoji===second.emoji){// 配对成功first.isMatched=true;second.isMatched=true;this.matchedCount+=1;this.firstIndex=-1;this.isChecking=false;}else{// 配对失败,延迟翻回// 记录本轮翻牌的 id(而非 index),避免 resetGame 后操作到新牌组constfirstId=this.cards[this.firstIndex].id;constsecondId=card.id;this.firstIndex=-1;// 用局部变量捕获当前 cards 引用,确保 setTimeout 操作同一批对象constcurrentCards=this.cards;setTimeout(()=>{// 通过 id 定位,防止 index 在 shuffle 后错位(本场景 index 稳定,双重保险)for(leti=0;i<currentCards.length;i++){if(currentCards[i].id===firstId||currentCards[i].id===secondId){currentCards[i].isFlipped=false;}}// 只在牌组未被替换时解锁(resetGame 已将 isChecking 重置,此处赋值幂等无副作用)if(this.cards===currentCards){this.isChecking=false;}},900);}}}

3.5 派生状态 —@Computed
@ComputedgetisGameOver():boolean{returnthis.matchedCount===FRUIT_EMOJIS.length;}

@Computed自动缓存,只在matchedCount变化时重新计算,驱动胜利弹层显示/隐藏。


3.6 UI 片段复用 —@Builder
@BuilderStatusBar(){/* 顶部状态栏 */}@BuilderCardGrid(){/* 卡片网格 */}build(){Column(){this.StatusBar()this.CardGrid()if(this.isGameOver){/* 胜利弹层 */}}}

@Builder拆分build()为命名片段,保持主build()简洁、无副作用。


四、运行方式

  1. 将上述代码保存到entry/src/main/ets/pages/Index.ets(已写入)。
  2. 在 DevEco Studio 中点击Run或使用模拟器预览。
  3. 无需创建其他文件,所有逻辑均在单文件内完成。

五、游戏规则

操作行为
点击背面牌翻开,显示水果 emoji
翻开两张相同标记配对(变绿,不可再翻)
翻开两张不同900ms 后自动翻回
全部配对显示胜利弹层,展示翻牌次数
点击"重新开始"重置所有状态,重新洗牌
http://www.cnnetsun.cn/news/2743898.html

相关文章:

  • 从一次HTTPS握手失败排查说起:JDK8默认加密限制如何“坑”了你的Spring Boot应用
  • 别再手动拼接了!CAPL脚本中整型数组与Hex字符串互转的通用函数库(附完整源码)
  • 告别地址冲突!I3C总线动态地址分配(ENTDAA)保姆级流程与实战避坑
  • Surface Pro4电池鼓包别慌!手把手教你用吹风机+塑料板安全拆屏换电池(附SSD升级指南)
  • RAG系统实战:从Elasticsearch到混合检索与重排序落地
  • Grok-3技术解析与API实战指南
  • 如何用快马AI在5分钟内为你的软件搭建一个girigo式下载页面原型
  • 2026 年 AI 数字人直播系统全面测评:技术、成本与转化的深度博弈
  • 2026年6月Claude Code新技能:安装使用全指南
  • 从‘锅盖’到星链:一文读懂卫星天线角度的演变与底层原理(附极化角图解)
  • AI Mock 数据生成:Schema 解析与自动校验策略
  • MSK信号定时恢复MATLAB工具:Gardner误差检测+数字锁相环实现
  • 互联网大厂Java求职面试实战:Java SE、Spring生态与微服务全技术栈问答解析
  • 给Chromium动个小手术:手把手教你修改源码,让Audio指纹随机化(附完整代码)
  • STM32F4系列通用步进电机梯形加减速驱动工程(含可烧录hex与HAL裸机实现)
  • MATLAB版GAPSO-BP回归预测工具:融合遗传与粒子群算法优化神经网络权值阈值,支持多输入多输出建模与五类指标自动评估
  • [智能体-241]:LangChain 工具机制解决:大模型怎么 “发号施令”、本地代码怎么 “就地干活”;MCP 协议解决:异地工具怎么被远端智能体发现与调用,实现工具生态分布式解耦;
  • 注塑模具设计避坑指南:以灭火器模具为例,详解侧抽芯与冷却系统那些容易出错的地方
  • 从无人机到VR手柄:聊聊ESKF(误差状态卡尔曼滤波)在姿态融合里的实战
  • 从无人机到VR手套:聊聊IMU姿态解算在实际产品中的那些“坑”
  • 如何在Windows上快速处理PDF:零编译终极工具指南
  • 不只是NEC:用STM32解码并存储格力空调等复杂红外协议(附波形分析)
  • 从Pikachu到遥感影像:用EISeg 2.6交互式分割,5分钟搞定你的第一个标注项目
  • yuzu模拟器游戏参数修改终极指南:解锁Switch游戏隐藏玩法
  • RippleNet知识图谱推荐系统Python可运行代码包(含Book/Yelp/Music/ML多数据集+毕设级注释)
  • Appium Inspector保姆级配置指南:从Desired Capabilities到连接真机/模拟器
  • C语言写的跨平台硬件指纹采集工具:CPU/硬盘序列号、网卡IP/MAC及物理链路状态一键获取
  • OA审批流踩坑记:事务、状态流转与通知推送的3个实战细节
  • Qwen3.6-Plus实战指南:智能体编程能力与VS Code深度集成
  • 别再为AI画风不统一发愁了!手把手教你用Midjourney的sref功能搞定风格一致性