Игра «Тетрис»

Классический вариант игры «Тетрис»

Файл 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);

7 Comments

  1. Greetings! Very useful advice within this article! It is the little changes that produce the biggest changes. Many thanks for sharing!

  2. Aw, this was an extremely nice post. Spending some time and actual effort to make a really good article… but what can I say… I put things off a lot and don’t manage to get anything done.

  3. wonderful issues altogether, you just won a new reader. What could you suggest about your publish that you made a few days in the past? Any certain?

  4. I don’t even know how I ended up here, but I thought this post was great. I don’t know who you are but definitely you are going to a famous blogger if you aren’t already 😉 Cheers!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *