0

I'm fairly new to coding and am trying to create a Tetris game. However, I've run into a few errors where I don't know the solution. Within the javascript I'm getting the error Uncaught TypeError: Cannot read property 'classList/forEach' of undefined in two separate sections.

The error for "forEach" appears at "//draw/undraw tetros" and the error for classList appears at the bottom of the code at classList.add('tetromino').

If anyone knows how I can fix this, it would be much appreciated. :)

document.addEventListener('DOMContentLoaded', () => {
document.querySelector('.grid');
let squares = Array.from(document.querySelectorAll('.grid div'));
const ScoreDisplay = document.querySelector('#score');
const StartBtn = document.querySelector('#start-button');
const width = 10;
let nextRandom = 0;

// The Tetrominoes//
const lTetromino = [
  [1, width+1, width*2+1, 2],
  [width, width+1, width+2, width*2+2],
  [1, width+1, width*2+1, width*2],
  [width, width*2, width*2+1, width*2+2]
  ]

const zTetromino = [
  [0, width, width+1, width*2+1],
  [width+1, width+2, width*2, width*2+1],
  [0, width, width+1, width*2+1],
  [width+1, width+2, width*2, width*2+1]
  ]

const tTetromino = [
 [1, width, width+1, width+2],
 [1, width+1, width+2, width*2+1],
 [width, width+1, width+2, width*2+1],
 [1, width+1, width*2+1]
 ]

const oTetromino = [
 [0, 1, width, width+1],
 [0, 1, width, width+1],
 [0, 1, width, width+1],
 [0, 1, width, width+1]
 ]

const iTetromino = [
 [1, width+1, width*2+1, width*3+1],
 [width, width+1, width+2, width+3],
 [1, width+1, width*2+1, width*3+1],
 [width, width+1, width+2, width+3]
]

const theTetrominoes = [lTetromino, zTetromino, tTetromino, oTetromino, iTetromino]

let currentPosition = 4
let currentRotation = 0

//randomly select a tetromino and its first rotation
let random = Math.floor(Math.random()*theTetrominoes.length)
let current = theTetrominoes[random][0]

// draw tetromino
function draw() {
  current.forEach(index => {
    squares[currentPosition + index].classList.add('tetromino')

})
}

//undraw the Tetrominoe
function undraw() {
  current.forEach(index => {
   squares[currentPosition + index].classList.remove('tetromino')

})
}

//make the tetromino move down every second
timerId = setInterval(moveDown, 1000)

//assign funtion to keycodes
function control(e) {
  if(e.keyCode === 37) {
    moveLeft()
  } else if (e.keyCode === 38) {
    rotate()
  } else if (e.keyCode === 39) {
    moveRight()
  } else if (e.keyCode === 40) {
    moveDown()
  }
}

document.addEventListener('keyup', control)

//move down function
function moveDown() {
  undraw()
  currentPosition += width
  draw()
  freeze()
}

//freeze
function freeze() {
  if(current.some(index => squares[currentPosition + index + width].classList
  .contains('taken'))) {
    current.forEach(index => squares[currentPosition + index].classList.add('taken'))
    //start a new tetro falling
    random = nextRandom
    nextRandom = Math.floor(Math.random() * theTetrominoes.length)
    current = theTetrominoes[random][currentRotation]
    currentPosition = 4
    draw()
    displayShape()
  }
}

//move the tetro left, unless is at the edge or there is a blockage
  function moveLeft() {
  undraw()
  const isAtLeftEdge = current.some(index => (currentPosition + index) % width === 0)

  if(!isAtLeftEdge) currentPosition -=1

  if(current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
    currentPosition +=1
}

draw()
}

//move the tetro right, unless is at the edge or there is a blockage
  function moveRight() {
  undraw()
  const isAtRightEdge = current.some(index => (currentPosition + index) % width
  === width -1)

  if(!isAtRightEdge) currentPosition +=1

  if(current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
    currentPosition -=1
  }
  draw()
}

//rotate retro
function rotate() {
  undraw()
  currentRotation ++
  if(currentRotation === current.length) { //if the current rotation gets to 4, make it go back to 0
    currentRotation = 0
  }
  current = theTetrominoes[random][currentRotation]
  draw()
}

//show up-next tetro in mini-grid
const displaySquares = document.querySelectorAll('mini-grid div')
const displayWidth = 4
let displayIndex = 0

// the tetro without currentRotation
const upNextTetrominoes = [
  [1, displayWidth+1, displayWidth*2+1, 2], //lTetromino
  [0, displayWidth, displayWidth+1, displayWidth*2+1], //zTetromino
  [1, displayWidth, displayWidth+1, displayWidth+2], //tTetromino
  [0, 1, displayWidth, displayWidth+1], //oTetromino
  [1, displayWidth+1, displayWidth*2+1, displayWidth*3+1] //iTetromino
]

//display the shape in the mini-grid display
function displayShape() {
  //remove any trace of a tetromino form the entire grid
  displaySquares.forEach(square => {
    square.classList.remove('tetromino')
  })
  upNextTetrominoes[nextRandom].forEach( index => {
    displaySquares[displayIndex + index].classList.add('tetromino')
  })
}


})
1

1 Answer 1

0

Please provide minimal reproducible example. However with the code provided following seem the problems

Problem 1

The error for "forEach" appears at "//draw/undraw tetros"

This is because you are nesting arrays at 3 level but trying to get like this let current = theTetrominoes[random][0] which means you are trying to access 2d array which it's not.

Solution

Try to make it 2d array or access it like 3d array:

theTetrominoes[random][0][desired_index]

Problem 2

error for classList appears at the bottom of the code at classList.add('tetromino')

You are passing index as the first parameter to forEach() which in fact is an actual item stored.

Solution

You should do something like this:

current.forEach((item, index) => {
      console.log(index)
    });
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.