2025-04-11 11:34:10 +02:00

667 lines
14 KiB
JavaScript

const board = document.getElementById('tetris-canvas');
const scoreElement = document.getElementById('score-value');
const loadMenu = document.getElementById('load-menu');
const mainMenu = document.getElementById('main-menu');
const pauseMenu = document.getElementById('pause-menu');
const startButton = document.getElementById('start-button');
const pauseButton = document.getElementById('pause-button');
const preview = document.getElementById('preview-canvas');
startButton.addEventListener('click', () =>
{
startGame();
});
pauseButton.addEventListener('click', () =>
{
pauseGame();
});
const boardContext = board.getContext('2d');
const previewContext = preview.getContext('2d');
boardContext.fillStyle = 'black';
boardContext.fillRect(0, 0, board.width, board.height);
const img = new Image();
img.src = '../img/PieceTetris.png';
let endDownInterval;
let oppacity = 255;
let downInterval;
let rightInterval;
let leftInterval;
let keyPress = [];
let score = 0;
let level = 0;
let lines = 0;
let speed = 1000;
let pause = false;
let gameOver = false;
const templatePiece = [
[ // ok
[3, 0],
[4, 0],
[5, 0],
[6, 0],
[4.5, 0.5]
],
[
[3, 1],
[4, 1],
[5, 1],
[5, 0],
[4, 1]
],
[ // ok
[3, 1],
[4, 1],
[5, 1],
[3, 0],
[4, 1]
],
[ // ok
[3, 0],
[4, 0],
[4, 1],
[5, 1],
[4, 1]
],
[
[3, 1],
[4, 1],
[4, 0],
[5, 0],
[4, 1]
],
[ // ok
[3, 0],
[4, 0],
[4, 1],
[5, 0],
[4, 0]
],
[ // ok
[4, 0],
[5, 0],
[4, 1],
[5, 1],
[4.5, 0.5]
]
];
const templateColor = [
[255, 0, 0, 255],
[0, 255, 0, 255],
[0, 0, 255, 255],
[255, 255, 0, 255],
[0, 255, 255, 255],
[255, 0, 255, 255],
[255, 40, 130, 255]
];
const speedSecondsToBotomPerLevel = [
15.974, //0
14.31, //1
12.646, //2
10.982, //3
9.318, //4
7.654, //5
5.99, //6
4.326, //7
2.662, //8
1.997, //9
1.664, //10
1.664, //11
1.664, //12
1.331, //13
1.331, //14
1.331, //15
0.998, //16
0.998, //17
0.998, //18
0.666, //19
0.666, //20
0.666, //21
0.666, //22
0.666, //23
0.666, //24
0.666, //25
0.666, //26
0.666, //27
0.666, //28
0.333 //29
];
let currentPiece = [];
let nextPiece = [];
let color = [];
let nextColor = [];
let boardData = [];
const MOVELEFT = 1;
const MOVERIGHT = 2;
const MOVEDOWN = 3;
const ROTATE = 4;
const MOVEDOWNFAST = 5;
const RESPAWN = 6;
let history = [];
function startGame() {
pause = false;
gameOver = false;
boardData = [];
currentPiece = [];
color = [];
history = [];
for (let i = 0; i < 10; i++) {
boardData[i] = [];
for (let j = 0; j < 20; j++) {
boardData[i][j] = [0, 0, 0, 255];
}
}
score = 0;
lines = 0;
level = 0;
speed = 1000;
scoreElement.innerText = score;
mainMenu.classList.add('hidden');
loadMenu.classList.add('hidden');
board.classList.add('hidden');
board.classList.remove('hidden');
iniGame();
refresh();
}
function pauseGame() {
if (pause) {
pause = false;
initAndChangeSpeedDrop();
} else {
pause = true;
clearDownInterval();
clearInterval(endDownInterval);
}
}
function iniGame() {
// Initialisation de la vitesse de chute
speed = (speedSecondsToBotomPerLevel[level]/20) * 1000;
spawnPiece();
// Intervalle pour faire tomber la pièce
downInterval = setInterval(() => {
moveDown();
refresh();
}, speed);
}
function drawTetisWithOppacity(x, y, color, oppacity) {
boardContext.drawImage(img, x, y, board.width/10, board.width/10);
const imageData = boardContext.getImageData(x, y, board.width/10, board.width/10);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = data[i] * color[0] / 255;
data[i + 1] = data[i + 1] * color[1] / 255;
data[i + 2] = data[i + 2] * color[2] / 255;
data[i + 3] = data[i + 3] * oppacity / 255;
}
boardContext.putImageData(imageData, x, y);
}
function drawTetrisOnThePreview(x, y, color) {
let width = 0;
let height = 0;
for (let i = 0; i < nextPiece.length - 1; i++) {
let piece = nextPiece[i];
width = Math.max(width, piece[0]);
height = Math.max(height, piece[1]);
}
x = x + (preview.width/5 - width * preview.width/5) / 2;
y = y + (preview.height/5 - height * preview.width/10) / 2;
previewContext.drawImage(img, x, y, preview.width/5, preview.width/5);
const imageData = previewContext.getImageData(x, y, preview.width/5, preview.width/5);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = data[i] * color[0] / 255;
data[i + 1] = data[i + 1] * color[1] / 255;
data[i + 2] = data[i + 2] * color[2] / 255;
data[i + 3] = data[i + 3] * color[3] / 255;
}
previewContext.putImageData(imageData, x, y);
}
function drawTetris(x, y, color) {
drawTetisWithOppacity(x, y, color, 255);
}
function drawCurrentPiece() {
for (let i = 0 ; i < currentPiece.length - 1; i++) {
let piece = currentPiece[i];
drawTetisWithOppacity(piece[0] * board.width/10, piece[1] * board.width/10, color, oppacity);
}
}
function drawBoard() {
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 20; j++) {
if (!(boardData[i][j][0] == 0 && boardData[i][j][1] == 0 && boardData[i][j][2] == 0)) {
drawTetris(i * board.width/10, j * board.width/10, boardData[i][j]);
}
}
}
}
function clearBoard() {
boardContext.fillStyle = 'black';
boardContext.fillRect(0, 0, board.width, board.height);
}
function drawGrid() {
boardContext.strokeStyle = 'gray'; // Couleur des lignes du quadrillage
boardContext.lineWidth = 0.5; // Épaisseur des lignes
// Dessiner les lignes verticales
for (let x = 0; x <= board.width; x += board.width / 10) {
boardContext.beginPath();
boardContext.moveTo(x, 0);
boardContext.lineTo(x, board.height);
boardContext.stroke();
}
// Dessiner les lignes horizontales
for (let y = 0; y <= board.height; y += board.height / 20) {
boardContext.beginPath();
boardContext.moveTo(0, y);
boardContext.lineTo(board.width, y);
boardContext.stroke();
}
}
function displayPreview() {
previewContext.fillStyle = 'black';
previewContext.fillRect(0, 0, preview.width, preview.height);
for (let i = 0; i < nextPiece.length - 1; i++) {
let piece = nextPiece[i];
drawTetrisOnThePreview(piece[0] * preview.width/5, piece[1] * preview.width/5, nextColor);
}
}
function refresh() {
clearBoard();
drawGrid();
drawBoard();
drawCurrentPiece();
displayPreview();
}
function loadTetris() {
clearDownInterval();
clearInterval(endDownInterval);
oppacity = 255;
currentPieceToBoard();
checkLine();
spawnPiece();
}
function currentPieceToBoard() {
if (currentPiece.length != 0) {
for (let i = 0; i < currentPiece.length - 1; i++) {
let piece = currentPiece[i];
boardData[piece[0]][piece[1]] = color; // Copie du tableau color
}
}
}
function spawnPiece() {
const random = Math.floor(Math.random() * templatePiece.length);
if (nextPiece.length == 0) {
for (let i = 0; i < templatePiece[random].length; i++) {
nextPiece.push([templatePiece[random][i][0], templatePiece[random][i][1]]);
}
nextColor = templateColor[random];
}
currentPiece = nextPiece;
nextPiece = [];
for (let i = 0; i < templatePiece[random].length; i++) {
nextPiece.push([templatePiece[random][i][0], templatePiece[random][i][1]]);
}
color = nextColor;
nextColor = templateColor[random];
history.push([RESPAWN, random]);
}
function ifMoveTo(x, y) {
return canMoveTo(x, y, currentPiece);
}
function canMoveTo(x, y, piece) {
for (let i = 0; i < piece.length - 1; i++) {
if (piece[i][0] + x < 0 || piece[i][0] + x >= 10 || piece[i][1] + y >= 20 || ifPiece(piece[i][0] + x, piece[i][1] + y)) {
return false;
}
}
return true;
}
function ifRotate(piece) {
for (let i = 0; i < piece.length - 1; i++) {
if (piece[i][0] < 0 || piece[i][0] >= 10 || piece[i][1] >= 20 || ifPiece(piece[i][0], piece[i][1])) {
return false;
}
}
return true;
}
function ifPiece(x, y) {
if (x < 0 || x >= 10 || y >= 20) {
return true;
}
if (y < 0) {
return false;
}
if (boardData[x][y][0] == 0 && boardData[x][y][1] == 0 && boardData[x][y][2] == 0) {
return false;
}
return true;
}
function rotate() {
if (currentPiece.length == 0) {
return;
}
let currentPieceCopy = [];
for (let i = 0; i < currentPiece.length; i++) {
currentPieceCopy.push([currentPiece[i][0], currentPiece[i][1]]);
}
const center = currentPieceCopy[currentPieceCopy.length - 1];
for (let i = 0; i < currentPiece.length - 1; i++) {
const x = currentPieceCopy[i][0] - center[0];
const y = currentPieceCopy[i][1] - center[1];
currentPieceCopy[i][0] = center[0] - y;
currentPieceCopy[i][1] = center[1] + x;
}
if (ifRotate(currentPieceCopy)) {
currentPiece = currentPieceCopy;
history.push([ROTATE, 0]);
}
else {
for (let x = -1; x <= 1; x++) {
for (let y = 0; y >= -1; y--) {
if (canMoveTo(x, y, currentPieceCopy)) {
moveToPiece(x, y, currentPieceCopy);
currentPiece = currentPieceCopy;
history.push([ROTATE, 0]);
x = 2;
y = -2;
}
}
}
}
checkEndDrop();
}
function checkEndDrop() {
clearInterval(endDownInterval);
oppacity = 255;
if (!ifMoveTo(0, 1)) {
clearDownInterval();
endDownInterval = setInterval(() => {
oppacity -= 5;
if (oppacity <= 60) {
loadTetris();
}
refresh();
}
, 11);
}
else if (!downInterval) {
clearDownInterval();
initAndChangeSpeedDrop();
}
}
function clearDownInterval() {
clearInterval(downInterval);
downInterval = null;
}
function checkLine() {
let lineFilled = 0;
for (let i = 0; i < 20; i++) {
let check = true;
for (let j = 0; j < 10; j++) {
if (boardData[j][i][0] == 0 && boardData[j][i][1] == 0 && boardData[j][i][2] == 0) {
check = false;
break;
}
}
if (check) {
for (let j = i; j > 0; j--) {
for (let k = 0; k < 10; k++) {
boardData[k][j] = boardData[k][j - 1];
}
}
for (let k = 0; k < 10; k++) {
boardData[k][0] = [0, 0, 0, 255];
}
lineFilled++;
}
}
if (lineFilled == 1) {
score += 40;
}
else if (lineFilled == 2) {
score += 100;
}
else if (lineFilled == 3) {
score += 300;
}
else if (lineFilled == 4) {
score += 1200;
}
scoreElement.innerText = score;
lines += lineFilled;
level = Math.floor(lines / 10);
initAndChangeSpeedDrop();
}
function initAndChangeSpeedDrop() {
if (level > 29) {
speed = (speedSecondsToBotomPerLevel[29]/20) * 1000;
}
else {
speed = (speedSecondsToBotomPerLevel[level]/20) * 1000;
}
clearDownInterval();
downInterval = setInterval(() => {
moveDown();
refresh();
}, speed);
}
function moveTo(x, y) {
moveToPiece(x, y, currentPiece);
}
function moveToPiece(x, y, piece) {
for (let i = 0; i < piece.length; i++) {
piece[i][0] += x;
piece[i][1] += y;
}
checkEndDrop();
}
function moveDown() {
if (!ifMoveTo(0, 1) || currentPiece.length == 1) {
return false;
}
moveTo(0, 1);
history.push([MOVEDOWN, 0]);
return true;
}
function moveLeft() {
if (!ifMoveTo(-1, 0) || currentPiece.length == 1) {
return false;
}
moveTo(-1, 0);
history.push([MOVELEFT, 0]);
return true;
}
function moveRight() {
if (!ifMoveTo(1, 0) || currentPiece.length == 1) {
return false;
}
moveTo(1, 0);
history.push([MOVERIGHT, 0]);
return true;
}
function fasteDrop() {
while (ifMoveTo(0, 1)) {
moveDown();
}
clearDownInterval();
clearInterval(endDownInterval);
oppacity = 255;
loadTetris();
history.push([MOVEDOWNFAST, 0]);
}
document.addEventListener('keydown', (event) => {
if (event.key == 'ArrowUp' && !keyPress.includes('ArrowUp')) {
rotate();
} else if (event.key == 'ArrowDown' && !keyPress.includes('ArrowDown')) {
clearDownInterval();
downInterval = setInterval(() => {
moveDown();
refresh();
}, 50);
} else if (event.key == 'ArrowLeft' && !keyPress.includes('ArrowLeft')) {
moveLeft();
leftInterval = setInterval(() => {
moveLeft();
refresh();
}, 100);
} else if (event.key == 'ArrowRight' && !keyPress.includes('ArrowRight')) {
moveRight();
rightInterval = setInterval(() => {
moveRight();
refresh();
}, 100);
} else if (event.key == ' ' && !keyPress.includes(' ')) {
fasteDrop();
}
refresh();
console.log(event.key);
keyPress.push(event.key);
});
document.addEventListener('keyup', (event) => {
if (event.key == 'ArrowDown') {
initAndChangeSpeedDrop();
} else if (event.key == 'ArrowLeft') {
clearInterval(leftInterval);
} else if (event.key == 'ArrowRight') {
clearInterval(rightInterval);
}
keyPress = keyPress.filter((key) => {
return key != event.key;
});
});
img.onload = () => {
loadMenu.classList.add('hidden');
mainMenu.classList.remove('hidden');
}