如何在游戏暂停时正确停止倒计时定时器
发布时间 - 2026-02-03 00:00:00 点击率:次本文讲解如何通过增量时间(delta time)机制实现游戏倒计时的精准暂停与恢复,避免系统级时间持续累积导致计时失准。核心是仅在播放状态(playstate)下累加时间差,而非依赖全局起始时间戳。
在 Java 游戏开发中,使用 System.currentTimeMillis() 直接计算总耗时(如 elapsedTime = now - startTime)看似简洁,但一旦游戏进入暂停状态(如 gp.gameState == gp.pauseState),该方式会持续“偷跑”——因为 startTime 是固定不变的,而 System.currentTimeMillis() 永远向前推进。结果就是:暂停 5 秒后恢复,倒计时直接少掉 5 秒,严重破坏游戏公平性与体验。
✅ 正确解法:改用增量式时间累加(Delta Time Accumulation)
不再依赖单一初始时间点,而是每帧记录与上一帧的时间差(delta),仅在非暂停状态下将该差值累加到已用时间中。这样,暂停期间 delta 虽然仍可计算,但不会被计入 elapsed,从而实现逻辑上的“时间冻结”。
以下是适配你现有代码结构的推荐实现:
// 声明为类成员变量(确保生命周期贯穿整个游戏)
private long lastUpdateTime = System.currentTimeMillis();
private long accumulatedTime = 0; // 已实际流逝的毫秒数(仅在 playState 下增长)
private final long TOTAL_TIME_MS = 60_000; // 60秒 = 60,000 毫秒
// 在游戏主循环(如 gameLoop() 或 update() 方法中)调用:
public void updateTimer() {

long now = System.currentTimeMillis();
long delta = now - lastUpdateTime;
// ✅ 关键:仅当处于播放状态且有正向时间差时才累加
if (gp.gameState == gp.playState && delta > 0) {
accumulatedTime += delta;
lastUpdateTime = now; // 更新基准时间点
}
// 计算剩余时间(注意:remainingTime 是基于 accumulatedTime 的实时推导)
long remainingTime = TOTAL_TIME_MS - accumulatedTime;
if (remainingTime <= 0) {
remainingTime = 0;
gp.gameOver();
}
// 格式化显示(毫秒取余,避免浮点误差)
long ms = remainingTime % 1000;
long sec = (remainingTime / 1000) % 60;
long min = (remainingTime / 1000) / 60;
timeString = String.format("%02d:%02d:%03d", min, sec, ms);
}? 关键注意事项:
- lastUpdateTime 必须在每次成功累加 delta 后立即更新为 now,否则下一帧的 delta 会异常增大;
- 不要重置 lastUpdateTime 进入暂停态(如设为 System.currentTimeMillis()),否则恢复时会产生巨大 delta,造成跳秒;
- accumulatedTime 是唯一可信的“已用时间”,所有逻辑(包括超时判断、UI 更新)都应基于它,而非重新计算 now - startTime;
- 若需支持多次暂停/恢复,此方案天然兼容——无需保存 pauseTime 或手动减法,逻辑更健壮、更易维护。
? 进阶提示:
对于更高精度或跨平台一致性需求,可考虑使用 System.nanoTime() 替代 currentTimeMillis()(注意单位是纳秒,需除以 1_000_000 转毫秒),它不受系统时钟调整影响,更适合游戏时间计量。
采用增量累加模式后,你的倒计时将真正与游戏状态同步:暂停即停,恢复即续,彻底告别“时间偷跑”问题。
# java
# ai
# 游戏开发
# ui
# 倒计时
# 而非
# 已用
# 进阶
# 浮点
# 设为
# 上一
# 不受
# 下一
# 更高
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何用好域名打造高点击率的自主建站?
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
微信小程序 canvas开发实例及注意事项
移动端脚本框架Hammer.js
如何在景安云服务器上绑定域名并配置虚拟主机?
node.js报错:Cannot find module 'ejs'的解决办法
手机软键盘弹出时影响布局的解决方法
使用C语言编写圣诞表白程序
Python函数文档自动校验_规范解析【教程】
Python并发异常传播_错误处理解析【教程】
如何在阿里云高效完成企业建站全流程?
Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程
如何打造高效商业网站?建站目的决定转化率
香港服务器租用每月最低只需15元?
js代码实现下拉菜单【推荐】
音乐网站服务器如何优化API响应速度?
Laravel如何实现用户注册和登录?(Auth脚手架指南)
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
Swift中循环语句中的转移语句 break 和 continue
如何快速上传建站程序避免常见错误?
Laravel怎么发送邮件_Laravel Mail类SMTP配置教程
JavaScript数据类型有哪些_如何准确判断一个变量的类型
百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭
如何基于PHP生成高效IDC网络公司建站源码?
利用vue写todolist单页应用
Android GridView 滑动条设置一直显示状态(推荐)
Win11怎么设置默认图片查看器_Windows11照片应用关联设置
Laravel怎么实现支付功能_Laravel集成支付宝微信支付
javascript中的try catch异常捕获机制用法分析
Laravel项目怎么部署到Linux_Laravel Nginx配置详解
如何将凡科建站内容保存为本地文件?
网站制作价目表怎么做,珍爱网婚介费用多少?
如何挑选高效建站主机与优质域名?
Laravel怎么使用artisan命令缓存配置和视图
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框
如何在Windows 2008云服务器安全搭建网站?
C++时间戳转换成日期时间的步骤和示例代码
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
如何解决hover在ie6中的兼容性问题
免费视频制作网站,更新又快又好的免费电影网站?
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
在Oracle关闭情况下如何修改spfile的参数
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践
如何选择PHP开源工具快速搭建网站?
Laravel如何使用Vite进行前端资源打包?(配置示例)
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
Laravel怎么实现模型属性的自动加密
如何在腾讯云服务器上快速搭建个人网站?


