Классический вариант игры «Тетрис»
Файл index.html
<!DOCTYPE html>
<html>
<head>
<title>Tetris</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas" width="240" height="400"></canvas>
<script src="tetris.js"></script>
</body>
</html>
Файл tetris.js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const ROWS = 20;
const COLS = 10;
const BLOCK_SIZE = 20;
const colors = [
"#000000",
"#FF0000",
"#00FF00",
"#0000FF",
"#FFFF00",
"#00FFFF",
"#FF00FF",
"#C0C0C0",
];
const shapes = [
[
[1, 1],
[1, 1],
],
[
[0, 2, 0],
[2, 2, 2],
],
[
[0, 3, 3],
[3, 3, 0],
],
[
[4, 4, 0],
[0, 4, 4],
],
[
[5, 5, 5, 5],
],
[
[0, 6, 0, 0],
[0, 6, 0, 0],
[0, 6, 0, 0],
[0, 6, 0, 0],
],
[
[0, 0, 7],
[7, 7, 7],
[0, 0, 0],
],
];
let board = [];
let currentShape = null;
let currentX = 0;
let currentY = 0;
let score = 0;
function newShape() {
const shapeIndex = Math.floor(Math.random() * shapes.length);
const shape = shapes[shapeIndex];
currentShape = [];
for (let i = 0; i < shape.length; i++) {
currentShape[i] = [];
for (let j = 0; j < shape[i].length; j++) {
currentShape[i][j] = shape[i][j];
}
}
currentX = Math.floor((COLS - currentShape[0].length) / 2);
currentY = 0;
}
function init() {
for (let i = 0; i < ROWS; i++) {
board[i] = [];
for (let j = 0; j < COLS; j++) {
board[i][j] = 0;
}
}
newShape();
draw();
}
function drawBlock(x, y, color) {
ctx.fillStyle = colors[color];
ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
ctx.strokeStyle = "#000000";
ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (board[i][j]) {
drawBlock(j, i, board[i][j]);
}
}
}
for (let i = 0; i < currentShape.length; i++) {
for (let j = 0; j < currentShape[i].length; j++) {
if (currentShape[i][j]) {
drawBlock(currentX + j, currentY + i, currentShape[i][j]);
}
}
}
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText(`Score: ${score}`, 10, 30);
}
function moveDown() {
if (canMove(0, 1)) {
currentY++;
} else {
freeze();
clearLines();
newShape();
}
draw();
}
function canMove(dx, dy) {
for (let i = 0; i < currentShape.length; i++) {
for (let j = 0; j < currentShape[i].length; j++) {
if (currentShape[i][j]) {
const newX = currentX + j + dx;
const newY = currentY + i + dy;
if (newX < 0 || newX >= COLS || newY >= ROWS) {
return false;
}
if (newY < 0) {
continue;
}
if (board[newY][newX]) {
return false;
}
}
}
}
return true;
}
function freeze() {
for (let i = 0; i < currentShape.length; i++) {
for (let j = 0; j < currentShape[i].length; j++) {
if (currentShape[i][j]) {
board[currentY + i][currentX + j] = currentShape[i][j];
}
}
}
}
function clearLines() {
let linesCleared = 0;
for (let i = ROWS - 1; i >= 0; i--) {
let rowFilled = true;
for (let j = 0; j < COLS; j++) {
if (board[i][j] === 0) {
rowFilled = false;
break;
}
}
if (rowFilled) {
for (let k = i; k > 0; k--) {
for (let j = 0; j < COLS; j++) {
board[k][j] = board[k - 1][j];
}
}
linesCleared++;
i++;
}
}
if (linesCleared > 0) {
score += linesCleared * 10;
}
}
document.addEventListener("keydown", (event) => {
switch (event.keyCode) {
case 37:
if (canMove(-1, 0)) {
currentX--;
draw();
}
break;
case 38:
rotate();
draw();
break;
case 39:
if (canMove(1, 0)) {
currentX++;
draw();
}
break;
case 40:
moveDown();
break;
}
});
function rotate() {
const newShape = [];
for (let i = 0; i < currentShape[0].length; i++) {
newShape[i] = [];
for (let j = 0; j < currentShape.length; j++) {
newShape[i][j] = currentShape[currentShape.length - 1 - j][i];
}
}
currentShape = newShape;
if (!canMove(0, 0)) {
currentShape = oldShape;
}
}
init();
setInterval(moveDown, 500);