class MovingObject extends GameObject { constructor(game, x, y) { super(game, x, y); this.dir = {x: 0, y: 0}; this.speed = 1; this.turnTimeout = null; } changeDir(dir) { if (this.dir.x === dir.x && this.dir.y === dir.y) { return; } if (this.dir.x === dir.x || this.dir.y === dir.y) { clearTimeout(this.turnTimeout); this.dir = dir; return; } const isX = this.dir.x !== 0; let curPos; let dirPositive; if (isX) { curPos = this.x; dirPositive = this.dir.x > 0; } else if (this.dir.y !== 0) { curPos = this.y; dirPositive = this.dir.y > 0; } let targetSwitch; if (dirPositive) { targetSwitch = Math.ceil(curPos + 0.5) - 0.5; } else { targetSwitch = Math.floor(curPos - 0.5) + 0.5; } const distance = Math.abs(curPos - targetSwitch); const duration = distance / this.speed * 1000; clearTimeout(this.turnTimeout); this.turnTimeout = setTimeout(() => { if (isX) { this.x = targetSwitch; } else { this.y = targetSwitch; } this.dir = dir; }, duration); } update(deltaTime) { const ticks = Math.floor(deltaTime / 16); const tickLength = deltaTime / ticks; for(let i = 0; i < ticks; i++) { this.x += this.dir.x * (this.speed * tickLength / 1000); this.y += this.dir.y * (this.speed * tickLength / 1000); const nextTile = this.getNextTile(this.dir.x, this.dir.y); if (!nextTile.tile) { if (nextTile.distanceX <= 0.5 || nextTile.distanceY <= 0.5) { return; } } if (nextTile.tile.solid) { if (nextTile.distanceX <= 0.5) { this.x = nextTile.tile.x - this.dir.x + 0.5; } if (nextTile.distanceY <= 0.5) { this.y = nextTile.tile.y - this.dir.y + 0.5; } } } } getNextTile(offsetX, offsetY) { const tileX = Math.round(this.x - 0.5); const tileY = Math.round(this.y - 0.5); const nextX = tileX + offsetX; const nextY = tileY + offsetY; const distanceX = Math.abs(this.x - (offsetX >= 0 ? nextX : nextX + 1)); const distanceY = Math.abs(this.y - (offsetY >= 0 ? nextY : nextY + 1)); return { tile: this.game.map.getTile(nextX, nextY), distanceX: distanceX, distanceY: distanceY, }; } }