rjgMtIfGYu4OB4QkmjHAeAZy7ixF2fuByIYhJHQr

Membuat Game Ular (Snake)

Cara Membuat Game Ular (Snake)
Cara Membuat Game Ular (Snake) Klasik dengan JavaScript, HTML, dan CSS Murni

Siapa yang tidak kenal game Ular atau Snake? Game klasik ini adalah salah satu game paling ikonik yang pernah ada. Bagi Anda yang sedang belajar coding, membuat ulang game ini adalah salah satu proyek terbaik untuk mengasah kemampuan.

Mengapa? Karena game ini menyentuh semua konsep dasar yang penting: logika, game loop, input pengguna, dan deteksi tabrakan.

Dalam tutorial ini, kita akan membuat game Snake kita sendiri dari nol. Kita tidak akan menggunakan library atau game engine yang rumit. Hanya tiga pilar utama web: HTML, CSS, dan JavaScript murni.

Mari kita mulai!


Langkah 1: Struktur HTML (index.html)

Pertama, kita butuh "kerangka" untuk game kita. File HTML kita akan sangat sederhana. Bagian terpenting di sini adalah elemen <canvas>.

Anggap saja <canvas> sebagai papan tulis digital. Ini adalah area kosong tempat JavaScript akan "menggambar" ular, makanan, dan skor kita.

Buat file bernama index.html dan isi dengan kode berikut:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Game Ular</title>
    <!-- Menghubungkan file CSS kita -->
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Game Ular</h1>
    
    <!-- Ini adalah "layar" game kita -->
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    
    <div id="controls">
        <button id="startButton">Mulai Game</button>
        <p>Gunakan panah keyboard untuk bergerak.</p>
    </div>
    
    <!-- Menghubungkan file JavaScript kita (Wajib di paling bawah) -->
    <script src="script.js"></script>
</body>
</html>

Langkah 2: Mempercantik Tampilan dengan CSS (style.css)

Secara default, halaman kita akan terlihat membosankan. Kita akan menggunakan sedikit CSS untuk memberinya tampilan yang lebih profesional, seperti memberi latar belakang gelap dan menempatkan kanvas di tengah.

Buat file bernama style.css dan tambahkan ini:

body {
    background-color: #282c34; /* Latar belakang gelap */
    color: #ffffff; /* Teks putih */
    font-family: 'Arial', sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    margin: 0;
}

h1 {
    color: #61dafb; /* Biru terang */
    margin-bottom: 20px;
}

canvas {
    background-color: #000000; /* Latar belakang kanvas hitam */
    border: 5px solid #61dafb; /* Border biru terang */
    display: block;
    box-shadow: 0 0 20px rgba(97, 218, 251, 0.5); /* Efek bayangan */
}

#controls {
    margin-top: 20px;
    text-align: center;
}

#startButton {
    background-color: #21a1f1; /* Biru */
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 5px;
    font-size: 1.1em;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

#startButton:hover {
    background-color: #1a7bbd; /* Biru lebih gelap saat hover */
}

Langkah 3: Otak Game dengan JavaScript (script.js)

Ini adalah bagian inti dari proyek kita. Kita akan menulis logika yang mengatur pergerakan ular, kapan ia makan, dan kapan ia menabrak.

Buat file script.js dan mari kita isi.

Konsep Utama Logika JavaScript

Sebelum melihat kode lengkapnya, mari pahami konsep utamanya:

  1. Inisialisasi: Kita mengambil elemen <canvas> dari HTML dan mendapatkan "konteks" 2D-nya (ctx). ctx adalah objek yang memiliki semua metode untuk menggambar (seperti fillRect untuk menggambar kotak).
  2. Sistem Grid: Game Snake tidak bergerak per piksel, tapi per kotak (grid). Kita tentukan ukuran satu kotak (misal gridSize = 20).
  3. Tubuh Ular: Bagaimana cara menyimpan tubuh ular? Kita gunakan Array! Setiap elemen di array adalah objek {x, y} yang menyimpan koordinat satu segmen tubuh ular. snake[0] adalah kepalanya.
  4. Game Loop: Ini adalah "detak jantung" game kita. Kita gunakan setInterval() untuk menjalankan fungsi gameLoop berulang kali (misalnya, setiap 100 milidetik).
  5. Fungsi update(): Di dalam game loop, fungsi ini menghitung logika:
    • Membuat ular bergerak: Kita menambahkan kepala baru di depan array (unshift) dan menghapus ekornya (pop). Ini menciptakan ilusi gerakan.
    • Makan makanan: Jika kepala ular ada di posisi yang sama dengan makanan, kita tidak menghapus ekornya (pop). Ini membuat ular bertambah panjang.
    • Deteksi tabrakan: Kita periksa apakah kepala ular menabrak dinding atau menabrak segmen tubuhnya sendiri.
  6. Fungsi draw(): Fungsi ini juga ada di dalam game loop. Tugasnya:
    • Membersihkan seluruh kanvas (ctx.clearRect()).
    • Menggambar ulang ular di posisi barunya.
    • Menggambar ulang makanan.
    • Menggambar ulang skor (ctx.fillText()).
  7. Input Pengguna: Kita gunakan addEventListener('keydown') untuk mendengarkan tombol panah keyboard dan mengubah arah (dx, dy) pergerakan ular.

Kode script.js Lengkap

Berikut adalah kode lengkap untuk script.js, termasuk perbaikan untuk menampilkan skor yang telah kita diskusikan:

// --- Inisialisasi Kanvas ---
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d'); // Dapatkan konteks 2D untuk menggambar

const startButton = document.getElementById('startButton');

// --- Pengaturan Game ---
const gridSize = 20; // Ukuran satu kotak (sel) dalam piksel
const tileCount = canvas.width / gridSize; // Jumlah kotak (20)

let snake = [{ x: 10, y: 10 }]; // Posisi awal ular (mulai dari kotak ke-10,10)
let food = {}; // Objek untuk menyimpan posisi makanan
let dx = 0; // Perubahan posisi X (0 = tidak bergerak horizontal)
let dy = 0; // Perubahan posisi Y (0 = tidak bergerak vertikal)
let score = 0;
let gameOver = true; // Game dimulai dalam keadaan kalah (belum dimulai)
let gameInterval; // Untuk menyimpan ID interval game loop

// --- Fungsi Utama (Game Loop) ---
function gameLoop() {
    if (gameOver) {
        return; // Hentikan game loop jika game over
    }

    update(); // Perbarui logika game
    draw();   // Gambar ulang semua objek
}

// --- Fungsi Update Logika Game ---
function update() {
    const head = { x: snake[0].x + dx, y: snake[0].y + dy }; // Hitung posisi kepala baru

    // Periksa tabrakan dengan dinding
    if (
        head.x < 0 || head.x >= tileCount ||
        head.y < 0 || head.y >= tileCount
    ) {
        endGame();
        return;
    }

    // Periksa tabrakan dengan diri sendiri
    for (let i = 1; i < snake.length; i++) {
        if (head.x === snake[i].x && head.y === snake[i].y) {
            endGame();
            return;
        }
    }

    snake.unshift(head); // Tambahkan kepala baru ke depan array ular

    // Periksa apakah ular makan makanan
    if (head.x === food.x && head.y === food.y) {
        score++;
        generateFood(); // Hasilkan makanan baru
    } else {
        snake.pop(); // Hapus ekor jika tidak makan (ular bergerak)
    }
}

// --- Fungsi Gambar ---
function draw() {
    // Bersihkan kanvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Gambar ular
    for (let i = 0; i < snake.length; i++) {
        ctx.fillStyle = (i === 0) ? 'lime' : '#00b300'; // Kepala hijau terang, badan hijau gelap
        ctx.fillRect(snake[i].x * gridSize, snake[i].y * gridSize, gridSize, gridSize);
        ctx.strokeStyle = 'black'; // Garis pinggir kotak
        ctx.strokeRect(snake[i].x * gridSize, snake[i].y * gridSize, gridSize, gridSize);
    }

    // Gambar makanan
    ctx.fillStyle = 'red';
    ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);

    // Gambar skor
    ctx.fillStyle = 'white';
    ctx.font = '20px Arial';
    // Gunakan koordinat (35, 30) agar teks tidak terpotong
    ctx.fillText('Skor: ' + score, 35, 30); 

    // Tampilkan pesan Game Over jika game over
    if (gameOver) {
        ctx.fillStyle = 'white';
        ctx.font = '30px Arial';
        ctx.textAlign = 'center';
        ctx.fillText('GAME OVER!', canvas.width / 2, canvas.height / 2 - 20);
        ctx.font = '20px Arial';
        ctx.fillText('Skor Akhir: ' + score, canvas.width / 2, canvas.height / 2 + 10);
    }
}

// --- Fungsi untuk Menghasilkan Makanan Baru ---
function generateFood() {
    let newFoodX, newFoodY;
    let collisionWithSnake;

    do {
        newFoodX = Math.floor(Math.random() * tileCount);
        newFoodY = Math.floor(Math.random() * tileCount);
        collisionWithSnake = false;

        // Pastikan makanan tidak muncul di atas ular
        for (let i = 0; i < snake.length; i++) {
            if (newFoodX === snake[i].x && newFoodY === snake[i].y) {
                collisionWithSnake = true;
                break;
            }
        }
    } while (collisionWithSnake); // Ulangi jika makanan muncul di atas ular

    food = { x: newFoodX, y: newFoodY };
}

// --- Fungsi untuk Mengatur Arah Ular Berdasarkan Input Keyboard ---
function changeDirection(event) {
    // Hindari ular bergerak mundur ke dirinya sendiri
    const keyPressed = event.keyCode;
    const LEFT = 37;
    const UP = 38;
    const RIGHT = 39;
    const DOWN = 40;

    const goingUp = dy === -1;
    const goingDown = dy === 1;
    const goingLeft = dx === -1;
    const goingRight = dx === 1;

    if (keyPressed === LEFT && !goingRight) {
        dx = -1;
        dy = 0;
    }
    if (keyPressed === UP && !goingDown) {
        dx = 0;
        dy = -1;
    }
    if (keyPressed === RIGHT && !goingLeft) {
        dx = 1;
        dy = 0;
    }
    if (keyPressed === DOWN && !goingUp) {
        dx = 0;
        dy = 1;
    }
}

// --- Fungsi untuk Mengakhiri Game ---
function endGame() {
    gameOver = true;
    clearInterval(gameInterval); // Hentikan game loop
    startButton.style.display = 'block'; // Tampilkan tombol Mulai Game
    draw(); // Gambar ulang untuk menampilkan pesan Game Over
}

// --- Fungsi untuk Memulai Game Baru ---
function startGame() {
    // Reset semua variabel game
    snake = [{ x: 10, y: 10 }];
    dx = 0; // Ular tidak bergerak saat dimulai
    dy = 0;
    score = 0;
    gameOver = false;
    generateFood(); // Hasilkan makanan pertama

    startButton.style.display = 'none'; // Sembunyikan tombol Mulai Game

    // Hentikan game loop sebelumnya jika ada
    if (gameInterval) {
        clearInterval(gameInterval);
    }
    // Mulai game loop baru (ulang setiap 100ms)
    // Ubah 100 menjadi angka lebih besar (misal: 150) untuk game lebih lambat
    gameInterval = setInterval(gameLoop, 100);
}

// --- Event Listener ---
document.addEventListener('keydown', changeDirection); // Dengarkan tombol keyboard ditekan
startButton.addEventListener('click', startGame);     // Dengarkan klik tombol start

// Gambar tampilan awal game (sebelum dimulai)
draw();

Selamat! Anda baru saja membuat game Snake klasik menggunakan JavaScript murni. Anda telah belajar cara menggunakan HTML Canvas, mengelola state game dengan variabel, membuat game loop dengan setInterval, dan menangani input pengguna.

Proyek ini adalah dasar yang keren. Apabila merasa tertantang? Coba kembangkan game ini lebih lanjut:

  1. Skor Tertinggi: Gunakan localStorage di browser untuk menyimpan skor tertinggi (High Score) pemain.
  2. Kecepatan Bertambah: Buat game semakin sulit dengan membuat ular bergerak lebih cepat (mengurangi nilai setInterval) setiap kali makan 5 makanan.
  3. Grafik Lebih Baik: Ganti kotak-kotak sederhana dengan gambar (sprite) ular dan apel sungguhan menggunakan ctx.drawImage().

Teruslah coding dan selamat bersenang-senang!

Posting Komentar