tetris
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Tetris Klasik</title>
<style>
body {
background: #202028;
color: #fff;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
text-align: center;
margin-top: 40px;
}
canvas {
border: solid 4px #444;
background: #000;
border-radius: 5px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
}
h1 {
margin-bottom: 10px;
color: #0DC2FF;
text-transform: uppercase;
letter-spacing: 2px;
}
#score-container {
font-size: 24px;
margin-bottom: 20px;
}
#score-value {
font-weight: bold;
color: #F538FF;
}
.instructions {
margin-top: 20px;
color: #aaa;
font-size: 14px;
}
</style>
</head>
<body>
<h1>Tetris</h1>
<div id="score-container">Skor: <span id="score-value">0</span></div>
<canvas id="tetris" width="300" height="600"></canvas>
<div class="instructions">
Gunakan tombol <strong>Panah Atas/Bawah/Kiri/Kanan</strong> untuk bermain.
</div>
<script>
const canvas = document.getElementById('tetris');
const context = canvas.getContext('2d');
// Memperbesar skala agar 1 blok = 30 piksel
context.scale(30, 30);
// Daftar warna untuk setiap bentuk balok (Tetromino)
const colors = [
null,
'#FF0D72', // T (Pink)
'#0DC2FF', // O (Biru Muda)
'#0DFF72', // J (Hijau)
'#F538FF', // L (Ungu)
'#FF8E0D', // I (Oranye)
'#FFE138', // S (Kuning)
'#3877FF', // Z (Biru Tua)
];
// Matriks pembentuk balok
function createPiece(type) {
if (type === 'T') {
return [
[0, 0, 0],
[1, 1, 1],
[0, 1, 0],
];
} else if (type === 'O') {
return [
[2, 2],
[2, 2],
];
} else if (type === 'L') {
return [
[0, 3, 0],
[0, 3, 0],
[0, 3, 3],
];
} else if (type === 'J') {
return [
[0, 4, 0],
[0, 4, 0],
[4, 4, 0],
];
} else if (type === 'I') {
return [
[0, 5, 0, 0],
[0, 5, 0, 0],
[0, 5, 0, 0],
[0, 5, 0, 0],
];
} else if (type === 'S') {
return [
[0, 6, 6],
[6, 6, 0],
[0, 0, 0],
];
} else if (type === 'Z') {
return [
[7, 7, 0],
[0, 7, 7],
[0, 0, 0],
];
}
}
// Membuat papan permainan (Arena)
function createMatrix(w, h) {
const matrix = [];
while (h--) {
matrix.push(new Array(w).fill(0));
}
return matrix;
}
const arena = createMatrix(10, 20);
const player = {
pos: {x: 0, y: 0},
matrix: null,
score: 0,
};
// Fungsi menggambar matriks (Papan & Balok)
function drawMatrix(matrix, offset) {
matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
context.fillStyle = colors[value];
context.fillRect(x + offset.x, y + offset.y, 1, 1);
// Efek garis pada balok
context.fillStyle = "rgba(0,0,0,0.3)";
context.strokeRect(x + offset.x, y + offset.y, 1, 1);
context.lineWidth = 0.05;
}
});
});
}
function draw() {
// Bersihkan layar
context.fillStyle = '#000';
context.fillRect(0, 0, canvas.width, canvas.height);
// Gambar arena & pemain
drawMatrix(arena, {x: 0, y: 0});
drawMatrix(player.matrix, player.pos);
}
// Menyatukan balok yang sudah jatuh ke arena
function merge(arena, player) {
player.matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
arena[y + player.pos.y][x + player.pos.x] = value;
}
});
});
}
// Deteksi tabrakan (dengan dinding atau balok lain)
function collide(arena, player) {
const m = player.matrix;
const o = player.pos;
for (let y = 0; y < m.length; ++y) {
for (let x = 0; x < m[y].length; ++x) {
if (m[y][x] !== 0 &&
(arena[y + o.y] && arena[y + o.y][x + o.x]) !== 0) {
return true;
}
}
}
return false;
}
// Menurunkan balok
function playerDrop() {
player.pos.y++;
if (collide(arena, player)) {
player.pos.y--;
merge(arena, player);
playerReset();
arenaSweep();
updateScore();
}
dropCounter = 0;
}
// Menggeser balok
function playerMove(offset) {
player.pos.x += offset;
if (collide(arena, player)) {
player.pos.x -= offset; // Batalkan gerakan jika menabrak
}
}
// Memunculkan balok baru
function playerReset() {
const pieces = 'TJLOSZI';
player.matrix = createPiece(pieces[pieces.length * Math.random() | 0]);
player.pos.y = 0;
player.pos.x = (Math.floor(arena[0].length / 2)) -
(Math.floor(player.matrix[0].length / 2));
// Jika langsung menabrak saat muncul, Game Over (reset arena)
if (collide(arena, player)) {
arena.forEach(row => row.fill(0));
player.score = 0;
updateScore();
}
}
// Memutar balok
function playerRotate(dir) {
const pos = player.pos.x;
let offset = 1;
rotate(player.matrix, dir);
// Menangani benturan dengan dinding saat berputar
while (collide(arena, player)) {
player.pos.x += offset;
offset = -(offset + (offset > 0 ? 1 : -1));
if (offset > player.matrix[0].length) {
rotate(player.matrix, -dir); // Batalkan putaran
player.pos.x = pos;
return;
}
}
}
function rotate(matrix, dir) {
for (let y = 0; y < matrix.length; ++y) {
for (let x = 0; x < y; ++x) {
[
matrix[x][y],
matrix[y][x],
] = [
matrix[y][x],
matrix[x][y],
];
}
}
if (dir > 0) {
matrix.forEach(row => row.reverse());
} else {
matrix.reverse();
}
}
// Menghapus baris yang penuh dan menambah skor
function arenaSweep() {
let rowCount = 1;
outer: for (let y = arena.length - 1; y >= 0; --y) {
for (let x = 0; x < arena[y].length; ++x) {
if (arena[y][x] === 0) {
continue outer;
}
}
// Hapus baris yang penuh dan tambahkan baris kosong di atas
const row = arena.splice(y, 1)[0].fill(0);
arena.unshift(row);
++y;
// Sistem skor kelipatan ganda
player.score += rowCount * 10;
rowCount *= 2;
}
}
function updateScore() {
document.getElementById('score-value').innerText = player.score;
}
// Loop Permainan (Waktu berjalan)
let dropCounter = 0;
let dropInterval = 1000; // Balok turun otomatis setiap 1 detik
let lastTime = 0;
function update(time = 0) {
const deltaTime = time - lastTime;
lastTime = time;
dropCounter += deltaTime;
if (dropCounter > dropInterval) {
playerDrop();
}
draw();
requestAnimationFrame(update);
}
// Deteksi input dari keyboard
document.addEventListener('keydown', event => {
// Mencegah layar scroll ke bawah saat menekan panah
if([37, 38, 39, 40].indexOf(event.keyCode) > -1) {
event.preventDefault();
}
if (event.keyCode === 37) {
playerMove(-1); // Kiri
} else if (event.keyCode === 39) {
playerMove(1); // Kanan
} else if (event.keyCode === 40) {
playerDrop(); // Bawah
} else if (event.keyCode === 38) {
playerRotate(1); // Atas
}
});
// Memulai permainan
playerReset();
updateScore();
update();
</script>
</body>
</html>
Komentar
Posting Komentar