HarmonyOS应用开发实战:猫猫大作战-setInterval 定时器、100ms 物理周期、主循环与 ArkUI 帧的协同、暂停时短路返回
前言游戏和静态 UI 的本质区别是——UI 是事件驱动的用户点击才更新游戏是时间驱动的每帧更新物理无论用户是否交互。ArkUI 没有内置「游戏循环」需要开发者用setInterval自己搭主循环——每隔固定周期触发一次物理更新。本篇以「猫猫大作战」100ms 主循环为锚点把setInterval 定时器、100ms 物理周期、主循环与 ArkUI 帧的协同、暂停时短路返回四大要点讲透。提示本系列不讲 ArkTS 础语法与环境搭建假设你已跟完第 1–32 篇。本篇是阶段二第三篇。一、场景拆解游戏主循环回顾「猫猫大作战」主循环第 31 篇// 来源entry/src/main/ets/pages/Index.ets startGame() this.gameLoopTimer setInterval(() { if (this.gameState ! GameState.PLAYING) return; // ← 暂停时短路返回 this.cats this.gameEngine.updateCats(); // 物理更新 this.score this.gameEngine.getScore(); // 同步得分 this.combo this.gameEngine.getCombo(); // 同步连击 if (this.gameEngine.isGameOver()) { this.endGame(); } }, 100); // ← 100ms 周期核心问题为什么用setInterval而不是 ArkUI 的requestAnimationFrame为什么是 100ms改成 16ms60 FPS会怎样暂停时定时器还在跑怎么处理二、setInterval 定时器2.1 基本用法const timerId: number setInterval(() { console.info(每 100ms 触发一次); }, 100); // 停止 clearInterval(timerId);API 说明API作用setInterval(callback, delay)周期性触发回调返回 timer idclearInterval(timerId)停止定时器2.2 setInterval vs setTimeoutAPI触发适合setInterval(cb, 100)每 100ms 一次周期游戏主循环setTimeout(cb, 100)100ms 后一次单次倒计时、延迟动画实战经验主循环用 setInterval一次性延迟用 setTimeout。本系列第 35 篇会讲 spawnTimer也用 setInterval因为要周期生成猫咪。2.3 setInterval 的误差setInterval(callback, 100)的100ms是「最短间隔」不是「精确间隔」——如果回调执行耗 20ms下一帧间隔就是 120ms 而非 100ms。回调耗时实际周期误差1ms101ms1%20ms120ms20%100ms200ms100%关键经验回调内别做重计算——耗时超过周期会拖慢整个循环。本系列第 144 篇会专讲 TaskPool 并发把重计算丢到后台线程。三、100ms 物理周期的选择3.1 为什么是 100ms游戏主循环周期决定物理粒度——周期越短猫咪下落越平滑但 CPU 开销越大。周期帧率猫咪下落视觉CPU 开销适合16ms60 FPS极平滑高FPS 游戏33ms30 FPS平滑中ARPG100ms10 FPS格子跳跃本项目低消除/回合200ms5 FPS明显卡顿极低慢节奏策略本项目选 100ms 的原因消除类游戏节奏慢——猫咪每 100ms 下落一格玩家来得及反应。格子跳跃即原生视觉——猫咪本就是按格子摆放不需要 60 FPS 平滑过渡第 16 篇 position 动画做了 100ms 过渡补偿。CPU 开销低——10 FPS 更新引擎省电。3.2 改成 60 FPS 会怎样// 假设改成 16ms60 FPS this.gameLoopTimer setInterval(() { this.cats this.gameEngine.updateCats(); // 每 16ms 调一次 // ... }, 16);问题引擎按格子算物理——updateCats()每次cat.y 116ms 调一次 60 格/秒下落太快玩家看不清。CPU 浪费——引擎内部物理只支持「一格一格跳」60 FPS 调用 60 次但只产生 10 次实际位移50 次空跑。关键经验主循环周期要匹配物理粒度——格子游戏用 100ms连续物理用 16ms。3.3 position 动画补偿// 来源entry/src/main/ets/pages/Index.ets GameView() 猫咪层 ForEach(this.cats, (cat: Cat) { Column() { /* ... */ } .position({ x: ..., y: ... }) .animation({ duration: 100, curve: Curve.Linear }) // ← 100ms 动画 }, (cat: Cat) cat.id)协同机制主循环 100ms 改cat.y→ position 重新计算。.animation({ duration: 100 })让 position 从旧值平滑过渡到新值耗时 100ms。下一帧主循环再改cat.y→ 新的 100ms 动画开始。视觉上猫咪每 100ms 平滑下落一格而不是「瞬移」。关键经验主循环周期 position 动画时长——视觉最连贯。本系列第 55、56 篇会专讲 animateTo 与 animation 属性动画。四、暂停时短路返回4.1 短路守卫this.gameLoopTimer setInterval(() { if (this.gameState ! GameState.PLAYING) return; // ← 短路返回 this.cats this.gameEngine.updateCats(); this.score this.gameEngine.getScore(); this.combo this.gameEngine.getCombo(); if (this.gameEngine.isGameOver()) { this.endGame(); } }, 100);为什么不用 clearInterval 暂停方案优点缺点短路返回本项目续期无缝、代码简单定时器一直跑微量 CPUclearInterval 暂停CPU 零开销续期要重建定时器代码复杂实战经验短停暂停用短路返回长停结束用 clearInterval——暂停要能无缝续期结束要彻底清理。4.2 三种状态的短路行为gameState主循环行为spawnTimer 行为timeTimer 行为IDLE短路返回短路返回短路返回PLAYING正常执行正常执行正常执行PAUSED短路返回短路返回短路返回不计时间GAME_OVER短路返回短路返回短路返回关键经验所有定时器都先检查gameState PLAYING——暂停/结束时统一短路避免状态错乱。4.3 暂停后恢复pauseGame() { if (this.gameState GameState.PLAYING) { this.gameState GameState.PAUSED; } } resumeGame() { if (this.gameState GameState.PAUSED) { this.gameState GameState.PLAYING; } } **恢复流程** 1. resumeGame() 把 gameState 切回 PLAYING。 2. 下一个 100ms 主循环触发短路守卫通过**正常执行物理更新**。 3. **无需重建定时器**——定时器一直在跑只是暂停期被短路。 ## 五、完整主循环代码 ts // 来源entry/src/main/ets/pages/Index.ets Entry Component struct Index { State gameState: GameState GameState.IDLE; State score: number 0; State cats: Cat[] []; State combo: ComboInfo { count: 0, multiplier: 1, lastMergeTime: 0 }; State nextCatLevel: CatLevel CatLevel.SMALL; State highScore: number 0; State gameTime: number 0; private gameEngine: GameEngine new GameEngine(); private gameLoopTimer: number -1; private spawnTimer: number -1; private timeTimer: number -1; startGame() { this.clearTimers(); this.gameEngine.reset(); this.gameState GameState.PLAYING; this.score 0; this.cats []; this.gameTime 0; this.combo { count: 0, multiplier: 1, lastMergeTime: 0 }; this.nextCatLevel this.gameEngine.getNextCatLevel(); // 游戏主循环 - 100ms 更新物理本篇重点 this.gameLoopTimer setInterval(() { if (this.gameState ! GameState.PLAYING) return; // 短路守卫 this.cats this.gameEngine.updateCats(); // 物理更新 this.score this.gameEngine.getScore(); // 同步得分 this.combo this.gameEngine.getCombo(); // 同步连击 if (this.gameEngine.isGameOver()) { this.endGame(); } }, 100); // 自动生成猫咪第 35 篇专讲 this.spawnTimer setInterval(() { if (this.gameState ! GameState.PLAYING) return; if (this.gameEngine.getCatCount() GameConfig.MAX_CATS) { this.gameEngine.autoSpawnCat(); this.cats this.gameEngine.getAllCats(); this.nextCatLevel this.gameEngine.getNextCatLevel(); } }, GameConfig.SPAWN_RATE); // 计时器第 34 篇专讲 this.timeTimer setInterval(() { if (this.gameState GameState.PLAYING) { this.gameTime; } }, 1000); } pauseGame() { if (this.gameState GameState.PLAYING) { this.gameState GameState.PAUSED; } } resumeGame() { if (this.gameState GameState.PAUSED) { this.gameState GameState.PLAYING; } } endGame() { this.gameState GameState.GAME_OVER; this.maxCombo this.gameEngine.getMaxCombo(); this.mergeCount this.gameEngine.getMergeCount(); this.highestLevel this.gameEngine.getHighestLevel(); if (this.score this.highScore) { this.highScore this.score; } this.clearTimers(); } clearTimers() { if (this.gameLoopTimer ! -1) { clearInterval(this.gameLoopTimer); this.gameLoopTimer -1; } if (this.spawnTimer ! -1) { clearInterval(this.spawnTimer); this.spawnTimer -1; } if (this.timeTimer ! -1) { clearInterval(this.timeTimer); this.timeTimer -1; } } }六、踩坑提示6.1 忘记 clearTimers 导致定时器泄漏// ❌ 错误重新开始没清旧定时器 Button(重新开始).onClick(() { this.startGame(); // 旧的 gameLoopTimer 还在跑 }) // ✅ 正确startGame 内首行 clearTimers startGame() { this.clearTimers(); // 先清旧定时器 /* ... */ }后果不清旧定时器新游戏开始后有两套主循环并行——猫「闪现」两个循环都改 cats、得分「跳变」两个都改 score。6.2 timer id 用 string 而非 number// ❌ 错误setInterval 返回 number却声明 string private gameLoopTimer: string ; // ✅ 正确声明 number初始 -1 表示无定时器 private gameLoopTimer: number -1;6.3 暂停时 clearInterval 而非短路// ⚠️ 可以但繁琐暂停就 clearInterval恢复再 setInterval pauseGame() { clearInterval(this.gameLoopTimer); this.gameLoopTimer -1; } resumeGame() { this.gameLoopTimer setInterval(() { /* ... */ }, 100); // 要重建定时器 } // ✅ 推荐短路返回定时器一直在跑 pauseGame() { this.gameState GameState.PAUSED; // 主循环内 if 短路 } resumeGame() { this.gameState GameState.PLAYING; // 主循环自动续期 }6.4 回调内改 state 丢 this// ❌ 错误普通函数 this 不指向组件 setInterval(function () { this.cats this.gameEngine.updateCats(); // this 不是 Index }, 100); // ✅ 正确箭头函数保留外层 this setInterval(() { this.cats this.gameEngine.updateCats(); }, 100);本系列第 38 篇会专讲箭头函数 this 绑定。七、调试技巧console.info打周期主循环里 logDate.now()两次 log 差就是实际周期看误差。定时器泄漏排查DevEco Profiler 看 timer 数量正常游戏时 3 个重新开始后还是 3 个不是 6 个。暂停无效排查检查gameState是否真的切到PAUSED检查主循环短路守卫。猫闪现排查DevEco Profiler 看 timer 数量闪现说明有重复定时器。八、性能与最佳实践主循环周期匹配物理粒度——格子游戏 100ms连续物理 16ms。暂停用短路返回——比 clearInterval 重建更简洁无缝续期。结束用 clearInterval——彻底清理避免泄漏。startGame 首行 clearTimers——避免新旧定时器并行。回调内别做重计算——耗时超周期会拖慢循环重计算丢 TaskPool第 144 篇。回调用箭头函数保留 this——普通函数 this 不指向组件。总结本篇我们从 setInterval 主循环切入掌握了setInterval 定时器 API、100ms 物理周期的选择依据、主循环与 position 动画的协同、暂停时短路返回四大要点并给出了完整主循环代码。核心要点周期匹配物理粒度暂停短路不 clearIntervalstartGame 首行 clearTimers 防泄漏。下一篇我们将拆解计时器——秒级 gameTime 递增。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源「猫猫大作战」项目源码本仓库entry/src/main/ets/pages/Index.etssetInterval/clearInterval 官方文档HarmonyOS 定时器 API 参考ArkUI 动画与定时器协同最佳实践开源鸿蒙跨平台社区HarmonyOS 开发者官方文档首页系列索引本仓库articles/INDEX.md

相关新闻

魔兽争霸3终极兼容性修复工具:WarcraftHelper让你的经典游戏焕然新生

魔兽争霸3终极兼容性修复工具:WarcraftHelper让你的经典游戏焕然新生

魔兽争霸3终极兼容性修复工具:WarcraftHelper让你的经典游戏焕然新生 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸3在现…

2026/9/16 13:06:24 阅读更多 →
如何让数字PDF拥有真实扫描质感:3分钟快速解决方案

如何让数字PDF拥有真实扫描质感:3分钟快速解决方案

如何让数字PDF拥有真实扫描质感:3分钟快速解决方案 【免费下载链接】lookscanned.io 📚 LookScanned.io - Make your PDFs look scanned 项目地址: https://gitcode.com/gh_mirrors/lo/lookscanned.io 你是否曾为数字生成的PDF文档太过"完美…

2026/9/14 6:08:03 阅读更多 →
视觉SLAM核心技术实战:从稀疏特征到稠密建图的完整工程方案

视觉SLAM核心技术实战:从稀疏特征到稠密建图的完整工程方案

视觉SLAM核心技术实战:从稀疏特征到稠密建图的完整工程方案 【免费下载链接】slambook2 edition 2 of the slambook 项目地址: https://gitcode.com/gh_mirrors/sl/slambook2 在自动驾驶、机器人导航和增强现实等前沿技术领域,如何让机器仅凭视觉…

2026/9/18 16:26:09 阅读更多 →

最新新闻

gbrain v0.18.0 多源大脑(Multi-source Brains)迁移与配置实战:一个数据库承载多个知识仓库

gbrain v0.18.0 多源大脑(Multi-source Brains)迁移与配置实战:一个数据库承载多个知识仓库

人工智能RAGAgent 记忆MCP 服务知识管理 【免费下载链接】gbrain Garrys Opinionated OpenClaw/Hermes Agent Brain 项目地址: https://gitcode.com/gh_mirrors/gb/gbrain 点击查看 免费下载 本指南以 skills/migrations/v0.18.0.md 迁移文档为核心骨架&#xff0c…

2026/9/21 7:38:43 阅读更多 →
Flink Table SQL DELETE 语句完全指南:行级删除、语法与连接器实现机制

Flink Table SQL DELETE 语句完全指南:行级删除、语法与连接器实现机制

大数据流处理批处理数据工程 【免费下载链接】flink 项目地址: https://gitcode.com/gh_mirrors/fli/flink 点击查看 免费下载 DELETE 是 Flink Table API & SQL 提供的行级删除语句,用于按照 WHERE 条件批量删除目标表中的数据。本指南以 Flink 官…

2026/9/21 7:38:43 阅读更多 →
Paseo 插件实战:用 Timeline Transformer 把 Agent 推理过程改造成内联思维链渲染

Paseo 插件实战:用 Timeline Transformer 把 Agent 推理过程改造成内联思维链渲染

【免费下载链接】paseo Orchestrate multiple coding agents from desktop and mobile 项目地址: https://gitcode.com/gh_mirrors/pa/paseo 点击查看 免费下载 Paseo 的插件系统允许客户端通过 Timeline Transformer 与 Timeline Renderer 接管 Agent 时间线上任意…

2026/9/21 7:38:43 阅读更多 →
使用 MXNet C++ API 加载预训练模型完成图像分类推理:从模型文件到端到端预测的完整实战

使用 MXNet C++ API 加载预训练模型完成图像分类推理:从模型文件到端到端预测的完整实战

使用 MXNet C API 加载预训练模型完成图像分类推理:从模型文件到端到端预测的完整实战 【免费下载链接】mxnet Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Sc…

2026/9/21 7:37:43 阅读更多 →
Nomad 与 CGO:为什么 Linux 上的 Nomad 二进制必须启用 CGO

Nomad 与 CGO:为什么 Linux 上的 Nomad 二进制必须启用 CGO

Nomad 与 CGO:为什么 Linux 上的 Nomad 二进制必须启用 CGO 【免费下载链接】nomad Nomad is an easy-to-use, flexible, and performant workload orchestrator that can deploy a mix of microservice, batch, containerized, and non-containerized applications…

2026/9/21 7:37:43 阅读更多 →
gbrain Ingest Skill 完全指南:把会议、文章、媒体与对话结构化沉淀进个人大脑

gbrain Ingest Skill 完全指南:把会议、文章、媒体与对话结构化沉淀进个人大脑

gbrain Ingest Skill 完全指南:把会议、文章、媒体与对话结构化沉淀进个人大脑 【免费下载链接】gbrain Garrys Opinionated OpenClaw/Hermes Agent Brain 项目地址: https://gitcode.com/gh_mirrors/gb/gbrain Ingest 是 gbrain 技能体系中面向"输入侧…

2026/9/21 7:37:43 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →