📌 Pembuka
Pernah main game 2048? Game simpel tapi bikin nagih ini ternyata bisa kamu buat sendiri lho hanya dengan HTML, CSS, dan JavaScript! Dan tenang aja, nggak harus jago banget ngoding kok. Di artikel ini, kita akan bahas cara bikin game 2048 sendiri dari nol, lengkap dengan penjelasan kode dan tampilannya yang warna-warni dalam mode gelap!
Kalau kamu nonton videonya, kamu juga bisa langsung praktek sambil lihat kodenya di bawah ini. Yuk, langsung mulai!
🎯 Manfaat Proyek Ini
Bikin game 2048 bukan cuma seru, tapi juga punya banyak manfaat buat kamu yang ingin:
- Belajar JavaScript dasar hingga menengah
- Memahami cara kerja grid, event listener, dan logika game
- Melatih kemampuan membuat animasi sederhana
- Bikin proyek portofolio keren yang bisa dipamerin!
💻 Langkah 1: Struktur HTML-nya
Kita mulai dari HTML, yaitu kerangka utama tampilan game-nya. Di sini kita buat judul, skor, papan permainan, dan tombol level.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>2048 Neon Mode</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="hud">
<h1>2048 Neon</h1>
<div id="score-box">Score: <span id="score">0</span></div>
</div>
<div id="game-container"></div>
<div id="game-over" style="display:none;">Game Over</div>
<script src="script.js"></script>
</body>
</html>
🔍 Penjelasan:
<div id="board">adalah tempat grid game akan muncul.
<select id="level">buat milih ukuran papan (4x4, 5x5, dll).
<div id="game-over">akan tampil saat permainan mentok alias gak bisa gerak lagi.
🎨 Langkah 2: Gaya CSS-nya
Agar tampilan lebih keren dan menyala-nyala, kita pakai mode gelap dengan warna cerah untuk tiap kotak.
body {
margin: 0;
background: #121212;
font-family: 'Segoe UI', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
}
#hud {
margin: 20px;
text-align: center;
}
#score-box {
font-size: 24px;
margin-top: 10px;
color: #00f2ff;
text-shadow: 0 0 10px #00f2ff;
}
#game-container {
display: grid;
grid-template-columns: repeat(4, 100px);
grid-template-rows: repeat(4, 100px);
gap: 10px;
background: #1e1e1e;
padding: 10px;
border-radius: 15px;
box-shadow: 0 0 15px #0ff;
}
.tile {
width: 100px;
height: 100px;
background: #2c2c2c;
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
font-weight: bold;
color: #fff;
border-radius: 10px;
box-shadow: inset 0 0 10px #000;
transition: all 0.2s ease-in-out;
animation: pop 0.2s ease-in-out;
}
@keyframes pop {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
/* Neon levels */
.tile[data-value="2"] { background: #00f2ff; color: #000; box-shadow: 0 0 10px #00f2ff; }
.tile[data-value="4"] { background: #0ff; color: #000; box-shadow: 0 0 10px #0ff; }
.tile[data-value="8"] { background: #00ff9f; color: #000; box-shadow: 0 0 12px #00ff9f; }
.tile[data-value="16"] { background: #55ff00; color: #000; box-shadow: 0 0 13px #55ff00; }
.tile[data-value="32"] { background: #ffaa00; color: #000; box-shadow: 0 0 14px #ffaa00; }
.tile[data-value="64"] { background: #ff5500; color: #fff; box-shadow: 0 0 15px #ff5500; }
.tile[data-value="128"] { background: #ff0077; color: #fff; box-shadow: 0 0 16px #ff0077; }
.tile[data-value="256"] { background: #bb00ff; color: #fff; box-shadow: 0 0 17px #bb00ff; }
.tile[data-value="512"] { background: #5500ff; color: #fff; box-shadow: 0 0 18px #5500ff; }
.tile[data-value="1024"] { background: #00b3ff; color: #000; box-shadow: 0 0 19px #00b3ff; }
.tile[data-value="2048"] { background: #00ffdc; color: #000; box-shadow: 0 0 20px #00ffdc; }
#game-over {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(20, 20, 20, 0.95);
color: #ff0077;
font-size: 48px;
padding: 30px 60px;
border-radius: 20px;
box-shadow: 0 0 20px #ff0077, 0 0 40px #ff0077;
z-index: 100;
text-align: center;
font-weight: bold;
text-shadow: 0 0 10px #ff0077;
}
✨ Penjelasan:
- Warna latar belakang hitam (
#121212) untuk mode gelap.
- Elemen
.tilepunya animasi ringan dan warna mencolok denganbox-shadow.
.game-overdisembunyikan dulu, nanti ditampilkan saat permainan selesai.
⚙️ Langkah 3: Logika JavaScript-nya
Sekarang bagian pentingnya: logika permainan. Di sinilah kita mengatur gerakan kotak, skor, level, dan pengecekan game over.
const size = 4;
let board = [];
let score = 0;
function createBoard() {
const container = document.getElementById("game-container");
container.innerHTML = "";
board = [];
for (let r = 0; r < size; r++) {
board[r] = [];
for (let c = 0; c < size; c++) {
board[r][c] = 0;
const tile = document.createElement("div");
tile.classList.add("tile");
tile.id = `tile-${r}-${c}`;
container.appendChild(tile);
}
}
score = 0;
updateScore();
addRandomTile();
addRandomTile();
updateBoard();
}
function updateScore() {
document.getElementById("score").textContent = score;
}
function addRandomTile() {
let empty = [];
for (let r = 0; r < size; r++) {
for (let c = 0; c < size; c++) {
if (board[r][c] === 0) empty.push({ r, c });
}
}
if (empty.length === 0) return;
const { r, c } = empty[Math.floor(Math.random() * empty.length)];
board[r][c] = Math.random() < 0.9 ? 2 : 4;
}
function updateBoard() {
for (let r = 0; r < size; r++) {
for (let c = 0; c < size; c++) {
const tile = document.getElementById(`tile-${r}-${c}`);
tile.textContent = board[r][c] === 0 ? "" : board[r][c];
tile.dataset.value = board[r][c] || "";
tile.classList.remove("merge");
void tile.offsetWidth; // Restart animation
tile.classList.add("tile");
}
}
}
function slide(row) {
let arr = row.filter(val => val);
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] === arr[i + 1]) {
arr[i] *= 2;
score += arr[i];
arr[i + 1] = 0;
}
}
return arr.filter(val => val).concat(Array(size - arr.filter(val => val).length).fill(0));
}
function rotateLeft(matrix) {
const result = [];
for (let c = 0; c < size; c++) {
result[c] = [];
for (let r = size - 1; r >= 0; r--) {
result[c][size - 1 - r] = matrix[r][c];
}
}
return result;
}
function rotateRight(matrix) {
const result = [];
for (let c = 0; c < size; c++) {
result[c] = [];
for (let r = 0; r < size; r++) {
result[c][r] = matrix[size - 1 - r][c];
}
}
return result;
}
function handleInput(direction) {
let newBoard = board.map(row => row.slice());
if (direction === "ArrowLeft") {
newBoard = newBoard.map(slide);
} else if (direction === "ArrowRight") {
newBoard = newBoard.map(row => slide(row.reverse()).reverse());
} else if (direction === "ArrowUp") {
newBoard = rotateLeft(newBoard);
newBoard = newBoard.map(slide);
newBoard = rotateRight(newBoard);
} else if (direction === "ArrowDown") {
newBoard = rotateLeft(newBoard);
newBoard = newBoard.map(row => slide(row.reverse()).reverse());
newBoard = rotateRight(newBoard);
}
if (JSON.stringify(board) !== JSON.stringify(newBoard)) {
board = newBoard;
addRandomTile();
updateBoard();
updateScore();
}
}
window.addEventListener("keydown", (e) => {
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(e.key)) {
e.preventDefault();
handleInput(e.key);
}
});
createBoard();
function isGameOver() {
for (let r = 0; r < size; r++) {
for (let c = 0; c < size; c++) {
if (board[r][c] === 0) return false; // masih ada ruang
if (c < size - 1 && board[r][c] === board[r][c + 1]) return false; // horizontal bisa digabung
if (r < size - 1 && board[r][c] === board[r + 1][c]) return false; // vertikal bisa digabung
}
}
return true;
}
📘 Penjelasan:
- Fungsi
setupBoard()digunakan untuk inisialisasi game baru.
move(dir)mengatur pergerakan kotak sesuai arah tombol panah.
addRandomTile()menambahkan angka baru di papan.
isGameOver()memeriksa apakah tidak ada gerakan tersisa.
✅ Penutup
Itu dia tutorial lengkap membuat game 2048 versi kamu sendiri! Dari tampilan sampai logika, semua dibahas agar kamu bisa belajar dan bereksperimen sendiri.
Cocok banget buat kamu yang ingin bikin game mini atau pengen punya karya keren untuk dipamerin. Jangan lupa modifikasi sesuka hati — ubah warna, ukuran, atau tambahkan suara!
Semoga bermanfaat dan selamat ngoding! 🚀

Komentar
Posting Komentar