blocky-stacky-blitz / script.js
Prince-7878's picture
Create a tertis game
5802f4e verified
Raw
History Blame Contribute Delete
8.56 kB
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('tetris');
const ctx = canvas.getContext('2d');
// Scale canvas
const scale = window.devicePixelRatio;
canvas.width = Math.floor(canvas.clientWidth * scale);
canvas.height = Math.floor(canvas.clientHeight * scale);
ctx.scale(scale, scale);
// Game state
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = canvas.width / 10 / scale;
const COLORS = [
null,
'#3B82F6', // I
'#8B5CF6', // J
'#F59E0B', // L
'#10B981', // O
'#EF4444', // S
'#EC4899', // T
'#84CC16' // Z
];
let board = createBoard();
let piece = null;
let score = 0;
let gameOver = false;
let dropCounter = 0;
let lastTime = 0;
let dropInterval = 1000;
// Pieces
const PIECES = [
null,
{ shape: [[0,0,0,0], [1,1,1,1], [0,0,0,0], [0,0,0,0]], color: 'I' },
{ shape: [[2,0,0], [2,2,2], [0,0,0]], color: 'J' },
{ shape: [[0,0,3], [3,3,3], [0,0,0]], color: 'L' },
{ shape: [[0,4,4], [0,4,4], [0,0,0]], color: 'O' },
{ shape: [[0,5,5], [5,5,0], [0,0,0]], color: 'S' },
{ shape: [[0,6,0], [6,6,6], [0,0,0]], color: 'T' },
{ shape: [[7,7,0], [0,7,7], [0,0,0]], color: 'Z' }
];
// Game functions
function createBoard() {
return Array.from({length: ROWS}, () => Array(COLS).fill(0));
}
function createPiece() {
const randomIndex = Math.floor(Math.random() * 7) + 1;
return {
position: {x: Math.floor(COLS / 2) - 1, y: 0},
shape: PIECES[randomIndex].shape,
color: PIECES[randomIndex].color
};
}
function draw() {
// Clear canvas
ctx.fillStyle = '#111827';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw board
board.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
ctx.fillStyle = COLORS[value];
ctx.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
}
});
});
// Draw current piece
if (piece) {
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
ctx.fillStyle = COLORS[value];
ctx.fillRect(
(piece.position.x + x) * BLOCK_SIZE,
(piece.position.y + y) * BLOCK_SIZE,
BLOCK_SIZE,
BLOCK_SIZE
);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.strokeRect(
(piece.position.x + x) * BLOCK_SIZE,
(piece.position.y + y) * BLOCK_SIZE,
BLOCK_SIZE,
BLOCK_SIZE
);
}
});
});
}
}
function collide() {
for (let y = 0; y < piece.shape.length; y++) {
for (let x = 0; x < piece.shape[y].length; x++) {
if (piece.shape[y][x] !== 0 &&
(board[y + piece.position.y] === undefined ||
board[y + piece.position.y][x + piece.position.x] === undefined ||
board[y + piece.position.y][x + piece.position.x] !== 0)) {
return true;
}
}
}
return false;
}
function rotate() {
const rotated = [];
for (let y = 0; y < piece.shape[0].length; y++) {
const row = [];
for (let x = piece.shape.length - 1; x >= 0; x--) {
row.push(piece.shape[x][y]);
}
rotated.push(row);
}
const previousShape = piece.shape;
piece.shape = rotated;
if (collide()) {
piece.shape = previousShape;
}
}
function movePiece(direction) {
piece.position.x += direction;
if (collide()) {
piece.position.x -= direction;
}
}
function hardDrop() {
while (!collide()) {
piece.position.y++;
}
piece.position.y--;
merge();
removeRows();
piece = createPiece();
if (collide()) {
gameOver = true;
document.querySelector('custom-game-over').setAttribute('visible', 'true');
}
}
function merge() {
piece.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
board[y + piece.position.y][x + piece.position.x] = value;
}
});
});
}
function removeRows() {
let linesCleared = 0;
outer: for (let y = board.length - 1; y >= 0; y--) {
for (let x = 0; x < board[y].length; x++) {
if (board[y][x] === 0) {
continue outer;
}
}
const row = board.splice(y, 1)[0].fill(0);
board.unshift(row);
y++;
linesCleared++;
}
if (linesCleared > 0) {
score += calculateScore(linesCleared);
updateScoreDisplay();
}
}
function calculateScore(lines) {
switch(lines) {
case 1: return 100;
case 2: return 300;
case 3: return 500;
case 4: return 800;
default: return 0;
}
}
function updateScoreDisplay() {
document.querySelector('custom-score-display').setAttribute('score', score.toString());
}
function resetGame() {
board = createBoard();
piece = createPiece();
score = 0;
gameOver = false;
dropInterval = 1000;
updateScoreDisplay();
document.querySelector('custom-game-over').setAttribute('visible', 'false');
}
// Game loop
function update(time = 0) {
if (gameOver) return;
const deltaTime = time - lastTime;
lastTime = time;
dropCounter += deltaTime;
if (dropCounter > dropInterval) {
piece.position.y++;
if (collide()) {
piece.position.y--;
merge();
removeRows();
piece = createPiece();
if (collide()) {
gameOver = true;
document.querySelector('custom-game-over').setAttribute('visible', 'true');
}
}
dropCounter = 0;
}
draw();
requestAnimationFrame(update);
}
// Controls
document.addEventListener('keydown', event => {
if (gameOver) return;
switch(event.keyCode) {
case 37: // Left
movePiece(-1);
break;
case 39: // Right
movePiece(1);
break;
case 40: // Down
piece.position.y++;
if (collide()) {
piece.position.y--;
merge();
removeRows();
piece = createPiece();
if (collide()) {
gameOver = true;
document.querySelector('custom-game-over').setAttribute('visible', 'true');
}
}
dropCounter = 0;
break;
case 38: // Up
rotate();
break;
case 32: // Space
hardDrop();
break;
case 80: // P
// Pause logic would go here
break;
}
});
// Initialize game
piece = createPiece();
update();
// Custom element event listeners
document.addEventListener('start-game', resetGame);
document.addEventListener('reset-game', resetGame);
});