You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Math.floor()或.toFixed(2)时增量游戏数值显示异常求助

增量游戏数值显示异常问题解决

问题背景

开发增量游戏时,尝试格式化atoms.amount的显示(无小数或最多两位小数),出现两种异常:

  1. 使用Math.floor()处理累加值时,数值一直显示0,切换标签页后随机跳变
  2. 使用.toFixed(2)处理时,出现字符串拼接式的异常格式(如00.020.02...)

相关代码:

Pinia Store代码

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', () => {
  const stats = {
    timePlayed: 0
  }

  const atoms = {
    amount: 0,
    increment: 0.001,
    max: 10
  }

  return { atoms, stats }
})

GameLoop代码

import { useUserStore } from '@/stores/user'

const user = useUserStore()

let lastTime = null
let timeTotal = 0

setInterval(function gameLoop() {
  const time = performance.now()
  if (lastTime === null) {
    lastTime = time
  }
  const timeDelta = time - lastTime
  timeTotal += timeDelta
  lastTime = time
  updateGame(timeDelta, timeTotal)
}, 1000 / 60)

function updateGame(timeDelta, timeTotal) {
  user.atoms.amount += user.atoms.increment * timeDelta
  user.stats.timePlayed = Math.floor(timeTotal / 1000)
}

错误原因分析

  1. Math.floor()导致数值不更新:
    60fps下timeDelta约为16ms,0.001 * 16 = 0.016,Math.floor(0.016)结果为0,每次累加0自然数值一直是0。切换标签页后浏览器会降低定时器执行频率,timeDelta会大幅增加(比如1000ms),此时0.001*1000=1,Math.floor后得到1,所以数值跳变。

  2. .toFixed(2)导致字符串拼接:
    .toFixed()返回的是字符串类型,而user.atoms.amount初始是数字0,数字和字符串相加会触发字符串拼接,比如:

    • 第一次累加:0 + "0.02" = "00.02"
    • 第二次累加:"00.02" + "0.02" = "00.020.02"
      最终出现异常格式。

解决方案

核心原则:存储时保持数值类型,只在显示阶段做格式化处理,避免破坏数值的计算逻辑。

方案1:显示时格式化(推荐)

保持gameLoop和Store的数值计算逻辑不变,在组件模板中直接格式化显示:

  • 无小数显示:
<!-- Vue组件模板中 -->
<div>Atoms: {{ Math.floor(user.atoms.amount) }}</div>
  • 最多两位小数显示:
<div>Atoms: {{ user.atoms.amount.toFixed(2) }}</div>

或者使用更灵活的国际化格式化:

<div>Atoms: {{ new Intl.NumberFormat('zh-CN', { maximumFractionDigits: 2 }).format(user.atoms.amount) }}</div>

方案2:强制存储时限制小数位数(不推荐,会丢失精度)

如果一定要在累加时限制小数位数,需要把.toFixed()的结果转成数字类型:

function updateGame(timeDelta, timeTotal) {
  // 转成数字后再累加
  user.atoms.amount += Number((user.atoms.increment * timeDelta).toFixed(2))
  user.stats.timePlayed = Math.floor(timeTotal / 1000)
}

注意:这种方式会丢失部分精度,长期累加可能和实际数值有偏差,仅适合对精度要求极低的场景。

内容的提问来源于stack exchange,提问作者Tristan Lovasz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:25:25