Canvas飞船游戏循环中属性突变为NaN问题排查求助
问题排查与修复方案
嘿,我帮你仔细看了代码和你遇到的异常情况,很快就发现了几个关键问题,尤其是那个差点让整个更新逻辑失效的语法错误!
最致命的问题:for循环的多余分号
你看这段更新循环的代码:
setInterval(function(){ for(var i in gameState.ships); var ship = gameState.ships[i]; ship.update(); }, 1000/60);
这里的for(var i in gameState.ships);后面多了个分号!这直接让循环体变成了空语句,循环只是遍历了一遍gameState.ships但什么都没做。后面的var ship = gameState.ships[i];只会拿到循环结束后最后一个i的值——如果没有客户端连接,i会是undefined,这时候ship就是undefined,调用ship.update()就会把全局对象(浏览器里是window)的属性搞乱,导致你看到的x、y变成NaN,velocity出现极小值的情况。
修复方法
把分号去掉,用大括号包裹循环体,确保每个飞船都能被正确遍历更新:
setInterval(function(){ for(var i in gameState.ships) { var ship = gameState.ships[i]; ship.update(); } }, 1000/60);
飞船更新逻辑的其他问题
除了循环的语法错误,你的Ship类的update函数也有几个逻辑漏洞,会间接导致异常:
- 加速度太夸张:每次推进直接让
velocity +=1,按60帧每秒算,一秒钟速度就会涨到60,远超你设置的maxVelocity:8,虽然有上限判断,但这种瞬间加速的逻辑不符合预期,也容易引发浮点数精度问题。 - 重复计算位置:
Ship的update里自己计算了位置,而Entity原本的update也做了同样的事,导致位置被更新两次,逻辑混乱。 - 减速时没限制负数:当
velocity减到0以下时,会变成负数导致飞船反向移动,这应该不是你想要的效果。
优化后的Ship类
我调整了Ship的update逻辑,复用Entity的位置更新逻辑,同时修正加速度和减速的问题:
var Ship = function(x,y,angle){ var self = Entity(x,y,angle); self.isThrusting = false; self.maxVelocity = 8; self.bullets = {}; // 保存父类的update方法,避免被覆盖后丢失 var parentUpdate = self.update; self.update = function(){ if(self.isThrusting){ // 用更小的加速度,比如0.1,让加速更平滑 self.velocity += 0.1; // 限制最大速度 self.velocity = Math.min(self.velocity, self.maxVelocity); }else { // 减速时,确保速度不会降到0以下 self.velocity = Math.max(self.velocity - 0.05, 0); } // 调用父类的update处理位置移动,避免重复计算 parentUpdate.call(self); } return self; }
额外的防护措施
为了避免angle变成NaN导致位置计算异常,你可以在Entity的update里加个简单的检查:
var Entity = function(x,y,angle){ var self = { x:x, y:y, angle:angle, velocity:2 } self.update = function(){ // 确保角度是有效数字,防止NaN if(isNaN(self.angle)) { self.angle = 0; } self.x += self.velocity * Math.sin(self.angle); self.y -= self.velocity * Math.cos(self.angle); } return self; }
另外,别忘了处理客户端断开的情况,不然断开的客户端对应的飞船会留在gameState.ships里,导致后续更新出错:
io.sockets.on('connection', function(socket){ gameState.ships[socket.id] = new Ship(300,300, 0); // 客户端断开时移除对应的飞船 socket.on('disconnect', function() { delete gameState.ships[socket.id]; }); });
为什么会出现那些异常值?
- 当循环错误导致
ship是undefined时,调用ship.update()会把self指向全局对象,修改的是全局的x、y等属性,后续再访问就会出现混乱的数值。 angle变成NaN后,Math.sin(NaN)和Math.cos(NaN)都会返回NaN,直接导致x和y变成NaN。- 那些极小的velocity值是浮点数精度问题,多次加减小数后会出现接近0的极小值,通过
Math.max限制到0就能解决。
内容的提问来源于stack exchange,提问作者Noor
相关产品推荐
相关产品推荐

