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:
- Inisialisasi: Kita mengambil elemen
<canvas>dari HTML dan mendapatkan "konteks" 2D-nya (ctx).ctxadalah objek yang memiliki semua metode untuk menggambar (sepertifillRectuntuk menggambar kotak). - Sistem Grid: Game Snake tidak bergerak per piksel, tapi per kotak (grid). Kita tentukan ukuran satu kotak (misal
gridSize = 20). - 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. - Game Loop: Ini adalah "detak jantung" game kita. Kita gunakan
setInterval()untuk menjalankan fungsigameLoopberulang kali (misalnya, setiap 100 milidetik). - 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.
- Membuat ular bergerak: Kita menambahkan kepala baru di depan array (
- 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()).
- Membersihkan seluruh kanvas (
- 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:
- Skor Tertinggi: Gunakan
localStoragedi browser untuk menyimpan skor tertinggi (High Score) pemain. - Kecepatan Bertambah: Buat game semakin sulit dengan membuat ular bergerak lebih cepat (mengurangi nilai
setInterval) setiap kali makan 5 makanan. - 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