When player's computer stutters/he tabs out of game stopping requestAnimationFrame calls, movement system tied to the delta time creates a huge leap, bypassing probable collisions. This allows player to cheat, for example avoiding projectiles by tabbing out and tabbing back in. What are solutions to such a problem, other than pausing the game when delta time is too high?
Attached simple system suffering from this problem - run the code, tab out, wait a while, then tab back in - you shouldn't see the "PEW" in console.
function Box(x, y, w, h, moving) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.moving = !!moving;
this.colliding = false;
}
Box.prototype.move = function(dx, dy) {
this.x += dx;
this.y += dy;
};
Box.prototype.testCollision = function(target) {
return (Math.abs(this.x - target.x) * 2 < (this.w + target.w)) &&
(Math.abs(this.y - target.y) * 2 < (this.h + target.h))
;
};
var boxes = [
new Box(0, 0, 100, 100, true),
new Box(200, 200, 100, 100)
];
function updatePosition(dt)
{
var time = dt / 1000;
for (var i = boxes.length - 1; i >= 0; i--) {
if(boxes[i].moving) boxes[i].move(100 * time, 100 * time);
}
}
function updateCollision()
{
for (var i = boxes.length - 1; i >= 0; i--) {
for (var j = boxes.length - 1; j >= 0; j--) {
if (i === j) continue;
if(boxes[i].testCollision(boxes[j])) {
boxes[i].colliding = true;
boxes[j].colliding = true;
console.log("PEW");
} else {
boxes[i].colliding = false;
boxes[j].colliding = false;
}
}
}
}
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
function render()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = boxes.length - 1; i >= 0; i--) {
var box = boxes[i];
if (box.colliding) ctx.fillStyle = '#FF0000';
else ctx.fillStyle = '#BADA55';
ctx.fillRect(box.x, box.y, box.w, box.h);
}
}
var lastTime = 0;
function update(time)
{
var dt = time - lastTime;
updatePosition(dt);
updateCollision();
render();
lastTime = time;
requestAnimationFrame(update);
}
requestAnimationFrame(update);
<canvas width="500" height="500"></canvas>