'Creating a Tetris game [closed]
I was following the freecodecamp.org Tetris course, but I changed some things up. I used foreach but the syntax seems right and it matches the freecodecamp.org video syntax so I don't get what it wants. The problem does not show up every time it shows up when a new Tetromino is coming down or when I rotate the Tetromino too many times. I am getting these errors in the browser console:
Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
at draw (app.js:69:13)
at freeze (app.js:117:9)
at moveDown (app.js:105:5)
3app.js:75 Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
at undraw (app.js:75:13)
at moveDown (app.js:102:5)
2app.js:75 Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
at undraw (app.js:75:13)
at rotate (app.js:156:5)
at HTMLDocument.control (app.js:93:10)
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tetris</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h3>Score: 0<span id="score"></span></h3>
<button id="start-button">Start/Pause</button>
<div class="container">
<div class="grid"></div>
<div class="mini-grid"></div>
</div>
<script src="app.js"></script>
</body>
</html>
JS:
const grid = document.querySelector(".grid");
const miniGrid = document.querySelector(".mini-grid");
const scoreDisplay = document.querySelector("#score");
const startButton = document.querySelector("#start-button");
const width = 10;
for (let i = 1; i <= 210; i++) {
var divs = document.createElement('div');
if (i >= 201) {
divs.classList.add('taken');
}
grid.appendChild(divs);
}
for (let i = 1; i <= 16; i++) {
var div = document.createElement('div');
miniGrid.appendChild(div);
}
const squares = Array.from(document.querySelectorAll(".grid div"));
//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 = [
[width * 2, width + 1, width * 2 + 1, width + 2],
[0, width, width + 1, width * 2 + 1]
[width * 2, width + 1, width * 2 + 1, width + 2],
[0, width, width + 1, width * 2 + 1]
]
const tTetromino = [
[width, 1, width + 1, width + 2],
[1, width + 1, width * 2 + 1, width + 2],
[width, width + 1, width * 2 + 1, width + 2],
[width, 1, width + 1, width * 2 + 1]
]
const sTetromino = [
[0, width, 1, width +1],
[0, width, 1, width +1],
[0, width, 1, width +1],
[0, width, 1, 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, sTetromino, iTetromino];
let random = Math.floor(Math.random() * 4);
let currentRotation = Math.floor(Math.random() * 3);
let currentPosition = Math.floor(Math.random() * 7);
let current = theTetrominoes[random][currentRotation];
//draw the first rotation in the first teromino
function draw () {
current.forEach(index => {
squares[currentPosition + index].classList.add('tetromino');
})
}
function undraw () {
current.forEach(index => {
squares[currentPosition + index].classList.remove('tetromino');
})
}
//moving down
timerId = setInterval(moveDown, 350);
//assign functions to keyCodes
function control(e) {
if (e.keyCode === 37) {
moveLeft();
} else if (e.keyCode === 39) {
moveRight();
} else if (e.keyCode === 38) {
rotate();
} //else if (e.keyCode === 38) {
//}
}
document.addEventListener('keyup', control);
function moveDown() {
undraw();
currentPosition += width;
draw();
freeze();
}
//freeze function
function freeze() {
if (current.some(index => squares[currentPosition + width + index].classList.contains('taken'))) {
current.forEach(index => squares[currentPosition + index].classList.add('taken'));
//start a new tetromino
random = Math.floor(Math.random() * 4);
currentPosition = Math.floor(Math.random() * 7);
current = theTetrominoes[random][currentRotation];
draw();
}
}
//move the tetromino 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();
}
function moveRight() {
undraw();
const isAtRightEdge = current.some(index => (currentPosition + index) % width === 9)
if (!isAtRightEdge) {
currentPosition += 1;
}
if (current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
currentPosition -= 1;
}
draw();
}
//rotate the tetromino
function rotate() {
undraw();
currentRotation ++;
if(currentRotation === current.length) {
currentRotation = 0;
}
current = theTetrominoes[random][currentRotation];
draw();
}
CSS:
.container {
display: flex;
}
.grid {
width: 200px;
height: 400px;
display: flex;
flex-wrap: wrap;
background-color: yellow;
}
.grid div {
height: 20px;
width: 20px;
}
.mini-grid {
margin-left: 50px;
width: 80px;
height: 80px;
display: flex;
flex-wrap: wrap;
background-color: yellow;
}
.mini-grid div {
height: 20px;
width: 20px;
}
.tetromino {
background-color: blue;
}
Solution 1:[1]
Edit: You're missing a comma in zTetromino.
Also just in case:
I think the problem is here when checking the length:
currentRotation ++;
if(currentRotation === current.length) {
currentRotation = 0;
}
current = theTetrominoes[random][currentRotation];
The 'current' rotation would be something like:
[0, width, width + 1, width * 2 + 1]
You should be checking the max with the number of rotations instead, which seem to be 4 for every tetromino.
So either access the tetromino and count its rotations, or hard-code 4.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
