为什么Canvas动画中rectX、rectY全局变量会被赋值为NaN?已解决
Canvas 游戏循环坐标变为NaN问题解答
问题根因
核心问题出在首次调用gameLoop函数的逻辑上:
- 初始代码直接执行无参调用
gameLoop(),此时函数接收的timeStamp参数为undefined - 执行
secondsPassed = (timeStamp - oldTimeStamp) / 1000运算时,undefined - 0的结果为NaN - 后续
update函数中movingSpeed * secondsPassed的结果仍为NaN,数值变量与NaN累加后会被覆盖为NaN - 因为
NaN属于JavaScript合法的数值运算结果,所以控制台不会抛出显式报错
如果你检测到rectX曾被识别为字符串,需要额外检查其他业务逻辑中是否存在意外给坐标变量赋值字符串的操作,这类隐式类型转换也会导致累加结果异常。
修正逻辑说明
你提供的修正后代码解决了核心的参数传递问题:
- 去掉了直接无参调用
gameLoop()的写法,改为通过window.requestAnimationFrame触发首次执行:requestAnimationFrame会自动给回调函数传入高精度时间戳参数,保证首次计算的secondsPassed是合法数值 - 后续循环触发
gameLoop时,也通过匿名函数包裹确保timeStamp参数能正确传递,避免参数丢失
原始问题代码
const canvas = document.querySelector('#canvas') const context = canvas.getContext('2d') let rectX = 0 ; let rectY = 0; let secondsPassed = 0; let timeStamp = 0 let oldTimeStamp = 0; let movingSpeed = 50; gameLoop() // 错误点:无参调用,timeStamp为undefined function draw() { context.fillStyle = 'red'; context.fillRect(rectX, rectY, 150, 100); } function gameLoop(timeStamp) { // Calculate how much time has passed secondsPassed = (timeStamp - oldTimeStamp) / 1000; oldTimeStamp = timeStamp; update(secondsPassed); draw(); window.requestAnimationFrame(gameLoop); } function update(secondsPassed) { rectX += (movingSpeed * secondsPassed); rectY += (movingSpeed * secondsPassed); }
修正后代码
const canvas = document.querySelector('#canvas') const context = canvas.getContext('2d') let rectX = 0; let rectY = 0; let secondsPassed = 0; let oldTimeStamp = 0; let timeStamp = 0 let movingSpeed = 50; let timePassed = 0 function draw() { context.fillStyle = 'red'; context.fillRect(rectX, rectY, 150, 100); } function gameLoop(timeStamp) { // Calculate how much time has passed secondsPassed = (timeStamp - oldTimeStamp) / 1000; oldTimeStamp = timeStamp; // Pass the time to the update update(secondsPassed); draw(); window.requestAnimationFrame(function(timeStamp){gameLoop(timeStamp)}); } function update(secondsPassed) { // Use time to calculate new position rectX += (movingSpeed * secondsPassed); rectY += (movingSpeed * secondsPassed); } // 正确:通过requestAnimationFrame传参触发首次调用 window.requestAnimationFrame(function(timeStamp){gameLoop(timeStamp)});
内容的提问来源于stack exchange,提问作者Tomasnborges
相关产品推荐
相关产品推荐

