3
index.js:182 Uncaught TypeError: document.querySelector(...).keydown is not a function
    at index.js:182
Uncaught TypeError: Cannot read property '0' of undefined
    at Snake.move (index.js:82)
    at setInterval (index.js:171)

const random = (max) => (Math.random() * (max + 1)) | 0;

let c = document.getElementById('c'); let ctx = c.getContext('2d'); let width = c.width; let height = c.height; let blockSize = 10; let widthInBlocks = width / blockSize; let heightInBlocks = height / blockSize; let score = 0; let drawBorder = () => { ctx.fillStyle = 'Gray'; ctx.fillRect(0, 0, width, bBorderlockSize); ctx.fillRect(0, height - blockSize, width, blockSize); ctx.fillRect(width - blockSize, 0, blockSize, height); }; let drawScore = () => { ctx.font = '20px Courier'; ctx.fillStyle = 'Black'; ctx.textAlign = 'left'; ctx.textBaseline = 'top'; ctx.fillText('Счет: ' + score, blockSize, blockSize); }; let gameOver = () => { clearInterval(intervalId); ctx.font = '60px Courier'; ctx.fillStyle = 'Black'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText('Конец игры: ', width / 2, height / 2); }; let circle = (x, y, radius, fillCircle) => { ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2, false); if (fillCircle) { ctx.fill(); } else { ctx.stroke(); } }; let Block = function(col, row) { this.col = col; this.row = row; }; Block.prototype.drawSquare = (color) => { let x = this.col * blockSize; let y = this.row * blockSize; ctx.fillStyle = color; ctx.fillRect(x, y, blockSize, blockSize); }; Block.prototype.drawCircle = (color) => { let centerX = this.col * blockSize + blockSize / 2; let centerY = this.row * blockSIze + blockSize / 2; ctx.fillStyle = color; circle(centerX, centerY, blockSize / 2, true); }; Block.prototype.equal = (otherBlock) => { return this.col === otherBlock.col && this.row === otherBlock.row; }; let Snake = function() { this.segments = [ new Block(7, 5), new Block(6, 5), new Block(5, 5) ]; this.direction = 'right'; this.nextDirection = 'right'; }; Snake.prototype.draw = () => { for (let i = 0; i < this.segments.length; i++) { this.segments[i].drawSquare('Blue'); } }; Snake.prototype.move = () => { let head = this.segments[0]; let newHead; this.direction = this.nextDirection; switch (this.direction) { case 'right': newHead = new Block(head.col + 1, head.row); break; case 'down': newHead = new Block(head.col, head.row + 1); break; case 'left': newHead = new Block(head.col - 1, head.row); break; case 'up': newHead = new Block(head.col, head.row - 1); break; }; if (this.checkCollision(newHead)) { gameOver(); return; } this.segments.unshift(newHead); if (newHead.equal(apple.position)) { score++; apple.move(); } else { this.segments.pop() } };

Snake.prototype.checkCollision = (head) => { let leftCollusion = (head.col === 0); let topCollusion = (head.row === 0); let rightCollusion = (head.col === widthInBlocks - 1); let bottomCollusion = (head.col === heightInBlocks - 1); let wallCollusion = leftCollusion || topCollusion || rightCollusion || bottomCollusion; let selfCollusion = false; for (let i = 0; i < this.segments.length; i++) { if (head.equal(this.segments[i])) { selfCollusion = true; } } return wallCollusion || selfCollusion; };

Snake.prototype.setDirection = (newDirection) => {

if (this.direction === 'up' && newDirection === 'down') { return; } else if (this.direction === 'right' && newDirection === 'left') { return; } else if (this.direction === 'down' && newDirection === 'up') { return; } else if (this.direction === 'left' && newDirection === 'right') { return; } this.nextDirection = newDirection; }; let Apple = function() { this.position = new Block(10, 10); }; Apple.prototype.draw = () => { this.position.drawCircle('LimeGreen'); }; Apple.prototype.move = () => { let randomCol = Math.floor(random(widthInBlocks)) + 1; let randomRow = Math.floor(random(heightInBlocks)) + 1; this.position = new Block(randomCol, randomRow); }; let snake = new Snake; let apple = new Apple;

let intervalId = setInterval(() => { ctx.clearRect(0, 0, width, height); drawScore(); snake.move(); snake.draw(); apple.draw(); drawBorder(); }, 100); let directions = { 37: 'left', 38: 'up', 39: 'right', 40: 'down' }; document.querySelector('body').keydown((event) => { let newDirection = directions[event.keyCode]; if (newDirection !== undefined) { snake.setDirection(newDirection); } });

#canvas {
  width: 400px;
  height: 400px;
}
<canvas id="c"></canvas>
Grundy
  • 81,538
Forxz
  • 43

1 Answers1

3

Что касается первой ошибки:

document.querySelector('body').keydown((event) => {

keydown - это НЕ функция. Возможно тут сказалось влияние jQuery, в котором подписка на событие действительно выглядит так.

Для решения можно использовать метод addEventListener

document.querySelector('body').addEventListener('keydown',e => {...})

Что касается второй ошибки.

Проблема в чрезмерном увлечении стрелочными функциями.

this для стрелочных функций определяется в момент их создания (подробнее в вопросе Потеря контекста вызова)

В данном случае в момент создания, this ссылается на глобальный объект window, а не на ожидаемый объект sneak.

Решение обычное - использование в этих случаях обычных функций, а не стрелочных.

Grundy
  • 81,538