Возникли проблемы с моей игрой на JavaScript в стиле candy crush

#javascript #html

#javascript #HTML

Вопрос:

app.js startPage() функция вызывается через кнопку onclick в html, но при createBoard() вызове я получаю сообщение об ошибке:

Ошибка неперехваченного типа: не удается прочитать свойство ‘appendChild’ null.

Мне просто интересно, могу ли я что-нибудь сделать, чтобы исправить это, или в этом есть фатальный недостаток с точки зрения необходимости перезапуска с нуля. Спасибо

 //Initializing global variables
const grid = document.getElementById("grid");
const scoreDisplay = document.getElementById("score");
const width = 8;
const squares = [];
let score = 0;

const candyColors = [
  "url(images/red-candy.png)",
  "url(images/yellow-candy.png)",
  "url(images/orange-candy.png)",
  "url(images/purple-candy.png)",
  "url(images/green-candy.png)",
  "url(images/blue-candy.png)",
];

//Game Home Page

function startPage() {
  var myBut = document.getElementById("but");
  var button = document.getElementById("button");
  myBut.removeChild(button);
  createBoard();
}
//create your board
function createBoard() {
  for (let i = 0; i < width * width; i  ) {
    const square = document.createElement('div')
    square.setAttribute("draggable", true)
    square.setAttribute("id", i)
    let randomColor = Math.floor(Math.random() * candyColors.length)
    square.style.backgroundImage = candyColors[randomColor]
    grid.appendChild(square)
    squares.push(square)
  }
}


// Dragging the Blocks
let colorBeingDragged;
let colorBeingReplaced;
let squareIdBeingDragged;
let squareIdBeingReplaced;

squares.forEach((square) => square.addEventListener("dragstart", dragStart));
squares.forEach((square) => square.addEventListener("dragend", dragEnd));
squares.forEach((square) => square.addEventListener("dragover", dragOver));
squares.forEach((square) => square.addEventListener("dragenter", dragEnter));
squares.forEach((square) => square.addEventListener("drageleave", dragLeave));
squares.forEach((square) => square.addEventListener("drop", dragDrop));

function dragStart() {
  colorBeingDragged = this.style.backgroundImage;
  squareIdBeingDragged = parseInt(this.id);
  // this.style.backgroundImage = ''
}

function dragOver(e) {
  e.preventDefault();
}

function dragEnter(e) {
  e.preventDefault();
}

function dragLeave() {
  this.style.backgroundImage = "";
}

function dragDrop() {
  colorBeingReplaced = this.style.backgroundImage;
  squareIdBeingReplaced = parseInt(this.id);
  this.style.backgroundImage = colorBeingDragged;
  squares[squareIdBeingDragged].style.backgroundImage = colorBeingReplaced;
}

function dragEnd() {
  //What is a valid move?
  let validMoves = [
    squareIdBeingDragged - 1,
    squareIdBeingDragged - width,
    squareIdBeingDragged   1,
    squareIdBeingDragged   width,
  ];
  let validMove = validMoves.includes(squareIdBeingReplaced);

  if (squareIdBeingReplaced amp;amp; validMove) {
    squareIdBeingReplaced = null;
  } else if (squareIdBeingReplaced amp;amp; !validMove) {
    squares[squareIdBeingReplaced].style.backgroundImage = colorBeingReplaced;
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
  } else
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
}

//drop candies once some have been cleared
function moveIntoSquareBelow() {
  for (i = 0; i < 55; i  ) {
    if (squares[i   width].style.backgroundImage === "") {
      squares[i   width].style.backgroundImage =
        squares[i].style.backgroundImage;
      squares[i].style.backgroundImage = "";
      const firstRow = [0, 1, 2, 3, 4, 5, 6, 7];
      const isFirstRow = firstRow.includes(i);
      if (isFirstRow amp;amp; squares[i].style.backgroundImage === "") {
        let randomColor = Math.floor(Math.random() * candyColors.length);
        squares[i].style.backgroundImage = candyColors[randomColor];
      }
    }
  }
}

///Checking for Matches
//for row of Four
function checkRowForFour() {
  for (i = 0; i < 60; i  ) {
    let rowOfFour = [i, i   1, i   2, i   3];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    const notValid = [
      5,
      6,
      7,
      13,
      14,
      15,
      21,
      22,
      23,
      29,
      30,
      31,
      37,
      38,
      39,
      45,
      46,
      47,
      53,
      54,
      55,
    ];
    if (notValid.includes(i)) continue;

    if (
      rowOfFour.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 4;
      scoreDisplay.innerHTML = score;
      rowOfFour.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

//for column of Four
function checkColumnForFour() {
  for (i = 0; i < 39; i  ) {
    let columnOfFour = [i, i   width, i   width * 2, i   width * 3];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    if (
      columnOfFour.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 4;
      scoreDisplay.innerHTML = score;
      columnOfFour.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

//for row of Three
function checkRowForThree() {
  for (i = 0; i < 61; i  ) {
    let rowOfThree = [i, i   1, i   2];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    const notValid = [6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55];
    if (notValid.includes(i)) continue;

    if (
      rowOfThree.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 3;
      scoreDisplay.innerHTML = score;
      rowOfThree.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

//for column of Three
function checkColumnForThree() {
  for (i = 0; i < 47; i  ) {
    let columnOfThree = [i, i   width, i   width * 2];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    if (
      columnOfThree.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 3;
      scoreDisplay.innerHTML = score;
      columnOfThree.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

// Checks carried out indefintely - Add Butotn to clear interval for best practise
window.setInterval(function () {
  checkRowForFour();
  checkColumnForFour();
  checkRowForThree();
  checkColumnForThree();
  moveIntoSquareBelow();
}, 100);```
===========================================================================================
index.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Candy Crush</title>
    <link rel="stylesheet" href="style.css">
    <script src="app.js" charset="utf-8"></script>
    <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400amp;display=swap" rel="stylesheet">
  </head>
  <body>
    <div id = "but">
      <input id = "button" onclick = "startPage()" type="submit"/>
    </div>
    <div class="score-board">
      <h3>score</h3>
      <h1 id="score"></h1>
    </div>
    <div id="grid"></div>
  </body>
</html>
===========================================================================================
  
 

Ответ №1:

 //Initializing global variables
const grid = document.getElementById("grid");
const scoreDisplay = document.getElementById("score");
const width = 8;
const squares = [];
let score = 0;

const candyColors = [
  "url(images/red-candy.png)",
  "url(images/yellow-candy.png)",
  "url(images/orange-candy.png)",
  "url(images/purple-candy.png)",
  "url(images/green-candy.png)",
  "url(images/blue-candy.png)",
];

//Game Home Page

function startPage() {
  var myBut = document.getElementById("but");
  var button = document.getElementById("button");
  myBut.removeChild(button);
  createBoard();
}
//create your board
function createBoard() {
  for (let i = 0; i < width * width; i  ) {
    const square = document.createElement('div')
    square.setAttribute("draggable", true)
    square.setAttribute("id", i)
    let randomColor = Math.floor(Math.random() * candyColors.length)
    square.style.backgroundImage = candyColors[randomColor]
    grid.appendChild(square)
    squares.push(square)
  }
  squares.forEach((square) => square.addEventListener("dragstart", dragStart));
  squares.forEach((square) => square.addEventListener("dragend", dragEnd));
  squares.forEach((square) => square.addEventListener("dragover", dragOver));
  squares.forEach((square) => square.addEventListener("dragenter", dragEnter));
  squares.forEach((square) => square.addEventListener("drageleave", dragLeave));
  squares.forEach((square) => square.addEventListener("drop", dragDrop));
  start_interval();
}

// Dragging the Blocks
let colorBeingDragged;
let colorBeingReplaced;
let squareIdBeingDragged;
let squareIdBeingReplaced;

function dragStart() {
  colorBeingDragged = this.style.backgroundImage;
  squareIdBeingDragged = parseInt(this.id);
  // this.style.backgroundImage = ''
}

function dragOver(e) {
  e.preventDefault();
}

function dragEnter(e) {
  e.preventDefault();
}

function dragLeave() {
  this.style.backgroundImage = "";
}

function dragDrop() {
  colorBeingReplaced = this.style.backgroundImage;
  squareIdBeingReplaced = parseInt(this.id);
  this.style.backgroundImage = colorBeingDragged;
  squares[squareIdBeingDragged].style.backgroundImage = colorBeingReplaced;
}

function dragEnd() {
  //What is a valid move?
  let validMoves = [
    squareIdBeingDragged - 1,
    squareIdBeingDragged - width,
    squareIdBeingDragged   1,
    squareIdBeingDragged   width,
  ];
  let validMove = validMoves.includes(squareIdBeingReplaced);

  if (squareIdBeingReplaced amp;amp; validMove) {
    squareIdBeingReplaced = null;
  } else if (squareIdBeingReplaced amp;amp; !validMove) {
    squares[squareIdBeingReplaced].style.backgroundImage = colorBeingReplaced;
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
  } else
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
}

//drop candies once some have been cleared
function moveIntoSquareBelow() {
  for (i = 0; i < 55; i  ) {
    if (squares[i   width].style.backgroundImage === "") {
      squares[i   width].style.backgroundImage =
        squares[i].style.backgroundImage;
      squares[i].style.backgroundImage = "";
      const firstRow = [0, 1, 2, 3, 4, 5, 6, 7];
      const isFirstRow = firstRow.includes(i);
      if (isFirstRow amp;amp; squares[i].style.backgroundImage === "") {
        let randomColor = Math.floor(Math.random() * candyColors.length);
        squares[i].style.backgroundImage = candyColors[randomColor];
      }
    }
  }
}

///Checking for Matches
//for row of Four
function checkRowForFour() {
  for (i = 0; i < 60; i  ) {
    let rowOfFour = [i, i   1, i   2, i   3];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    const notValid = [
      5,
      6,
      7,
      13,
      14,
      15,
      21,
      22,
      23,
      29,
      30,
      31,
      37,
      38,
      39,
      45,
      46,
      47,
      53,
      54,
      55,
    ];
    if (notValid.includes(i)) continue;

    if (
      rowOfFour.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 4;
      scoreDisplay.innerHTML = score;
      rowOfFour.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

//for column of Four
function checkColumnForFour() {
  for (i = 0; i < 39; i  ) {
    let columnOfFour = [i, i   width, i   width * 2, i   width * 3];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    if (
      columnOfFour.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 4;
      scoreDisplay.innerHTML = score;
      columnOfFour.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

//for row of Three
function checkRowForThree() {
  for (i = 0; i < 61; i  ) {
    let rowOfThree = [i, i   1, i   2];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    const notValid = [6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55];
    if (notValid.includes(i)) continue;

    if (
      rowOfThree.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 3;
      scoreDisplay.innerHTML = score;
      rowOfThree.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

//for column of Three
function checkColumnForThree() {
  for (i = 0; i < 47; i  ) {
    let columnOfThree = [i, i   width, i   width * 2];
    let decidedColor = squares[i].style.backgroundImage;
    const isBlank = squares[i].style.backgroundImage === "";

    if (
      columnOfThree.every(
        (index) =>
          squares[index].style.backgroundImage === decidedColor amp;amp; !isBlank
      )
    ) {
      score  = 3;
      scoreDisplay.innerHTML = score;
      columnOfThree.forEach((index) => {
        squares[index].style.backgroundImage = "";
      });
    }
  }
}

// Checks carried out indefintely - Add Butotn to clear interval for best practise
function start_interval(){
    window.setInterval(function () {
      checkRowForFour();
      checkColumnForFour();
      checkRowForThree();
      checkColumnForThree();
      moveIntoSquareBelow();
    }, 100);
}
 

Ответ №2:

Добавьте defer атрибут к тегу вашего скрипта (необязательно async также атрибут). <script async defer src="app.js" charset="utf-8"></script>

Это гарантирует, что скрипт будет выполняться только после загрузки страницы, а сетка действительно существует. На данный момент он выполняется немедленно, до полной загрузки DOM.

Ответ №3:

Ошибка Uncaught TypeError: Cannot read property 'appendChild' of null указывает на то, что вы пытаетесь вызвать appendChild переменную null. Ошибка возникает в этой строке:

 grid.appendChild(square)
 

Убедитесь, что вы не присваиваете значение null grid при его инициализации.

 const grid = document.getElementById("grid");