Bikin Game Stickman Runner dari Nol Pakai HTML & JavaScript!
Halo para coder muda! ๐ Di sesi kali ini kita akan bikin game seru bareng โ Stickman Runner! Stickman lari, ada rintangan kaktus dan burung, dan kamu harus melompat menghindarinya. Semakin lama bertahan, skor kamu makin tinggi!
Yang paling keren: kita akan bikin semua ini dari nol โ baris demi baris โ pakai tiga teknologi yang sudah kalian pelajari: HTML, CSS, dan JavaScript. Yuk langsung gas! ๐
๐ง Konsep Coding yang Akan Kita Pelajari
Sebelum mulai, kita kenali dulu konsep apa saja yang akan dipakai dalam game ini. Jangan panik โ semua akan dijelaskan sambil kita coding!
| Konsep | Dipakai untuk | Teknologi |
|---|---|---|
| Canvas | Area menggambar game kita | HTML |
| Variabel | Menyimpan posisi, kecepatan, skor | JS |
| Fungsi (Function) | Memisahkan tugastiap bagian game | JS |
| Perulangan (Loop) | Game loop yang terus berjalan | JS |
| Kondisi (if/else) | Deteksi tabrakan, game over | JS |
| Object | Stickman, rintangan sebagai satu kesatuan | JS |
| Array | Menyimpan banyak rintangan sekaligus | JS |
| Event Listener | Mendeteksi tombol spasi / klik | JS |
Setelah 2 pertemuan, game kalian bisa: stickman bergerak dengan gravitasi, lompat double-jump, ada rintangan kaktus dan burung yang makin cepat, sistem skor, dan high score!
Sesi 1 Fondasi โ Canvas, Stickman & Gravitasi
Step 1 Buat File dan Struktur HTML Dasar
Buka VS Code, buat file baru bernama stickman.html, lalu ketik kode berikut:
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <title>Stickman Runner</title> <style> body { background: #1a1a2e; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: sans-serif; color: white; } canvas { border: 3px solid #e94560; border-radius: 8px; display: block; } </style> </head> <body> <h1>๐ Stickman Runner</h1> <canvas id="gameCanvas" width="600" height="250"></canvas> <script> // Kita ambil canvas dari HTML const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Gambar latar belakang untuk tes ctx.fillStyle = '#0f0f23'; ctx.fillRect(0, 0, 600, 250); // Gambar tanah ctx.fillStyle = '#2c3e50'; ctx.fillRect(0, 235, 600, 15); console.log('Canvas siap! ๐ฎ'); </script> </body> </html>
Simpan file (Ctrl+S), lalu buka di browser. Kalian akan lihat kotak hitam dengan garis tanah. Itu artinya canvas kita berhasil! Buka Console di F12 untuk cek pesan “Canvas siap!”
Step 2 Gambar Stickman dengan Canvas Drawing
Sekarang kita bikin fungsi untuk menggambar stickman. Ganti bagian <script> dengan kode berikut:
const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // ============================================ // VARIABEL STICKMAN // ============================================ let stickmanX = 80; // posisi horizontal let stickmanY = 180; // posisi vertikal // ============================================ // FUNGSI GAMBAR STICKMAN // ============================================ function gambarStickman(x, y) { const cx = x + 15; // titik tengah horizontal ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 3; ctx.lineCap = 'round'; // --- Kepala --- ctx.beginPath(); ctx.arc(cx, y, 10, 0, Math.PI * 2); ctx.fillStyle = '#ffffff'; ctx.fill(); // --- Badan --- ctx.beginPath(); ctx.moveTo(cx, y + 10); ctx.lineTo(cx, y + 35); ctx.stroke(); // --- Tangan kiri --- ctx.beginPath(); ctx.moveTo(cx, y + 17); ctx.lineTo(cx - 12, y + 30); ctx.stroke(); // --- Tangan kanan --- ctx.beginPath(); ctx.moveTo(cx, y + 17); ctx.lineTo(cx + 12, y + 30); ctx.stroke(); // --- Kaki kiri --- ctx.beginPath(); ctx.moveTo(cx, y + 35); ctx.lineTo(cx - 12, y + 55); ctx.stroke(); // --- Kaki kanan --- ctx.beginPath(); ctx.moveTo(cx, y + 35); ctx.lineTo(cx + 12, y + 55); ctx.stroke(); } // Gambar dulu langit + tanah ctx.fillStyle = '#0f0f23'; ctx.fillRect(0, 0, 600, 250); ctx.fillStyle = '#2c3e50'; ctx.fillRect(0, 235, 600, 15); // Panggil fungsi gambar stickman gambarStickman(stickmanX, stickmanY);
Coba ganti angka-angka di moveTo dan lineTo โ misalnya badan lebih panjang, atau tangan lebih lebar. Kalian bisa bikin stickman dengan gaya sendiri!
Step 3 Tambah Gravitasi & Lompatan
Ini bagian paling seru! Kita akan bikin stickman bisa jatuh karena gravitasi, dan bisa melompat ketika spasi ditekan. Ganti isi <script> dengan kode berikut:
const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // ============================================ // DATA STICKMAN โ kita gabungkan jadi OBJECT // ============================================ const stickman = { x: 80, y: 180, // posisi saat ini vy: 0, // kecepatan vertikal (- = naik, + = turun) groundY: 180, // posisi tanah jumpCount: 0 // hitungan lompatan (max 2 untuk double jump) }; const GRAVITASI = 0.6; const KEKUATAN_LOMPAT = -13; // ============================================ // FUNGSI GAMBAR STICKMAN // ============================================ function gambarStickman() { const cx = stickman.x + 15; const y = stickman.y; ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 3; ctx.lineCap = 'round'; ctx.beginPath(); ctx.arc(cx, y, 10, 0, Math.PI * 2); ctx.fillStyle = '#ffffff'; ctx.fill(); ctx.beginPath(); ctx.moveTo(cx, y + 10); ctx.lineTo(cx, y + 35); ctx.stroke(); ctx.beginPath(); ctx.moveTo(cx, y + 17); ctx.lineTo(cx - 12, y + 30); ctx.stroke(); ctx.beginPath(); ctx.moveTo(cx, y + 17); ctx.lineTo(cx + 12, y + 30); ctx.stroke(); ctx.beginPath(); ctx.moveTo(cx, y + 35); ctx.lineTo(cx - 12, y + 55); ctx.stroke(); ctx.beginPath(); ctx.moveTo(cx, y + 35); ctx.lineTo(cx + 12, y + 55); ctx.stroke(); } // ============================================ // UPDATE โ logika fisika setiap frame // ============================================ function update() { // Tambahkan gravitasi ke kecepatan vertikal stickman.vy += GRAVITASI; // Gerakkan stickman sesuai kecepatan stickman.y += stickman.vy; // Cek apakah sudah menyentuh tanah if (stickman.y >= stickman.groundY) { stickman.y = stickman.groundY; // snap ke tanah stickman.vy = 0; // stop jatuh stickman.jumpCount = 0; // reset hitungan lompatan } } // ============================================ // GAME LOOP โ ini yang membuat game berjalan! // ============================================ function gameLoop() { // 1. Bersihkan canvas ctx.clearRect(0, 0, 600, 250); // 2. Gambar latar belakang ctx.fillStyle = '#0f0f23'; ctx.fillRect(0, 0, 600, 250); ctx.fillStyle = '#2c3e50'; ctx.fillRect(0, 235, 600, 15); // 3. Update posisi stickman update(); // 4. Gambar stickman gambarStickman(); // 5. Ulangi terus menerus (60x per detik) requestAnimationFrame(gameLoop); } // ============================================ // KONTROL โ deteksi tombol spasi // ============================================ document.addEventListener('keydown', function(e) { if (e.code === 'Space') { e.preventDefault(); if (stickman.jumpCount < 2) { // Double jump! stickman.vy = KEKUATAN_LOMPAT; stickman.jumpCount++; } } }); // Mulai game loop! gameLoop();
Gravitasi = setiap frame, kecepatan turun bertambah 0.6. Seperti bola yang dilempar ke atas โ makin lama makin melambat, lalu jatuh. requestAnimationFrame membuat gameLoop dipanggil ~60 kali per detik!
Sesi 2 Rintangan, Skor & Game Over
Step 4 Tambah Rintangan Kaktus
Stickman sudah bisa lompat. Sekarang kita tambahkan kaktus yang bergerak dari kanan ke kiri! Tambahkan kode ini setelah bagian stickman (sebelum gameLoop):
// ============================================ // RINTANGAN // ============================================ let rintangan = []; // array untuk menyimpan semua kaktus let timerRintangan = 0; // penghitung waktu kemunculan const KECEPATAN = 4; // seberapa cepat rintangan bergerak // Fungsi membuat kaktus baru function buatKaktus() { const tinggi = 30 + Math.random() * 25; // tinggi acak 30-55 rintangan.push({ x: 620, // mulai dari kanan canvas y: 235 - tinggi, // posisi atas kaktus lebar: 20, tinggi: tinggi }); } // Fungsi gambar kaktus function gambarKaktus(k) { ctx.fillStyle = '#2ecc71'; // Batang utama ctx.fillRect(k.x + 5, k.y, 10, k.tinggi); // Cabang kiri ctx.fillRect(k.x, k.y + 8, 5, 12); // Cabang kanan ctx.fillRect(k.x + 15, k.y + 5, 5, 12); } // ============================================ // Tambahkan ke dalam gameLoop(): // ============================================ // Tulis ini DI DALAM fungsi gameLoop, setelah update() // Spawn kaktus setiap 80 frame timerRintangan++; if (timerRintangan >= 80) { buatKaktus(); timerRintangan = 0; } // Gerakkan dan gambar semua kaktus rintangan.forEach(function(k) { k.x -= KECEPATAN; // gerakkan ke kiri gambarKaktus(k); // gambar }); // Hapus kaktus yang sudah keluar layar (kiri) rintangan = rintangan.filter(function(k) { return k.x > -50; });
Step 5 Deteksi Tabrakan (Collision Detection)
Game butuh tahu kalau stickman menabrak kaktus. Ini disebut collision detection. Kita pakai teknik “AABB” โ membandingkan kotak pembatas dua objek:
// ============================================ // DETEKSI TABRAKAN // ============================================ let gameOver = false; function cekTabrakan(k) { // Kita kasih sedikit "ruang" agar tidak terlalu ketat const margin = 6; // Kotak stickman const sx = stickman.x + margin; const sy = stickman.y + margin; const sw = 30 - margin * 2; // lebar stickman const sh = 55 - margin * 2; // tinggi stickman // Cek apakah dua kotak bersentuhan const tabrakan = sx < k.x + k.lebar && sx + sw > k.x && sy < k.y + k.tinggi && sy + sh > k.y; if (tabrakan) { gameOver = true; console.log('Game Over! ๐ฅ'); } } // Panggil cekTabrakan untuk setiap kaktus di dalam gameLoop rintangan.forEach(function(k) { cekTabrakan(k); });
Step 6 Sistem Skor & Layar Game Over
Terakhir, kita tambahkan skor yang naik otomatis dan tampilan game over. Ini kode lengkap final kalian โ salin semua dan ganti file lama:
Kode di bawah adalah versi final yang sudah punya skor, high score, layar start, layar game over, dan kecepatan yang makin cepat. Ini hasil kerja keras 2 sesi!
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <title>Stickman Runner</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #1a1a2e; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; font-family: sans-serif; color: white; } h1 { color: #e94560; margin-bottom: 10px; font-size: 1.8rem; } #ui { display: flex; justify-content: space-between; width: 600px; padding: 8px 4px; } #score { color: #f5a623; font-weight: bold; } #rekor { color: #7ed6a7; font-weight: bold; } canvas { border: 3px solid #e94560; border-radius: 8px; display: block; } #petunjuk { margin-top: 8px; color: #aaa; font-size: 0.85rem; } </style> </head> <body> <h1>๐ Stickman Runner</h1> <div id="ui"> <span id="score">Score: 0</span> <span id="rekor">Rekor: 0</span> </div> <canvas id="gameCanvas" width="600" height="250"></canvas> <p id="petunjuk">โฌ Tekan SPASI atau klik layar untuk lompat</p> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const rekorEl = document.getElementById('rekor'); // === VARIABEL GAME === let gameJalan = false; let gameOver = false; let score = 0; let rekor = 0; let frame = 0; let kecepatan = 4; // === STICKMAN === const sm = { x: 80, y: 180, vy: 0, groundY: 180, jumpCount: 0 }; function lompat() { if (sm.jumpCount < 2) { sm.vy = -13; sm.jumpCount++; } } function updateStickman() { sm.vy += 0.6; sm.y += sm.vy; if (sm.y >= sm.groundY) { sm.y = sm.groundY; sm.vy = 0; sm.jumpCount = 0; } } function gambarStickman() { const cx = sm.x + 15, y = sm.y; ctx.strokeStyle = '#fff'; ctx.lineWidth = 3; ctx.lineCap = 'round'; ctx.beginPath(); ctx.arc(cx, y, 10, 0, Math.PI*2); ctx.fillStyle = '#fff'; ctx.fill(); [[cx, y+10, cx, y+35],[cx, y+17, cx-12, y+30], [cx, y+17, cx+12, y+30],[cx, y+35, cx-12, y+55], [cx, y+35, cx+12, y+55]].forEach(function(l) { ctx.beginPath(); ctx.moveTo(l[0],l[1]); ctx.lineTo(l[2],l[3]); ctx.stroke(); }); } // === RINTANGAN === let rintangan = [], timerR = 0; function buatKaktus() { const t = 30 + Math.random() * 25; rintangan.push({ x: 620, y: 235-t, lebar: 20, tinggi: t }); } function gambarKaktus(k) { ctx.fillStyle = '#2ecc71'; ctx.fillRect(k.x+5, k.y, 10, k.tinggi); ctx.fillRect(k.x, k.y+8, 5, 12); ctx.fillRect(k.x+15, k.y+5, 5, 12); } function cekTabrakan(k) { const m=6, sx=sm.x+m, sy=sm.y+m, sw=30-m*2, sh=55-m*2; if (sx < k.x+k.lebar && sx+sw > k.x && sy < k.y+k.tinggi && sy+sh > k.y) { gameOver = true; gameJalan = false; if (score > rekor) { rekor = score; rekorEl.textContent = `Rekor: ${rekor}`; } } } // === LAYAR TEKS === function tulisLayar(judul, sub, warna) { ctx.fillStyle = 'rgba(0,0,0,0.6)'; ctx.fillRect(0,0,600,250); ctx.fillStyle = warna; ctx.font = 'bold 36px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(judul, 300, 90); ctx.fillStyle = '#fff'; ctx.font = '18px sans-serif'; ctx.fillText(sub, 300, 130); ctx.fillStyle = '#f5a623'; ctx.font = 'bold 20px sans-serif'; ctx.fillText('Tekan SPASI / Klik untuk mulai', 300, 200); ctx.textAlign = 'left'; } // === GAME LOOP === function gameLoop() { ctx.clearRect(0,0,600,250); ctx.fillStyle='#0f0f23'; ctx.fillRect(0,0,600,250); ctx.fillStyle='#2c3e50'; ctx.fillRect(0,235,600,15); if (!gameJalan && !gameOver) { gambarStickman(); tulisLayar('STICKMAN RUNNER', 'Hindari kaktus! Double jump tersedia ๐ฆ ', '#e94560'); requestAnimationFrame(gameLoop); return; } if (gameOver) { gambarStickman(); rintangan.forEach(gambarKaktus); tulisLayar('GAME OVER!', `Score kamu: ${score}`, '#e94560'); requestAnimationFrame(gameLoop); return; } frame++; score = Math.floor(frame/6); kecepatan = 4 + Math.floor(score/200) * 0.8; scoreEl.textContent = `Score: ${score}`; timerR++; if (timerR >= Math.max(80 - Math.floor(score/100)*3, 35)) { buatKaktus(); timerR=0; } rintangan.forEach(function(k) { k.x-=kecepatan; gambarKaktus(k); cekTabrakan(k); }); rintangan = rintangan.filter(function(k){ return k.x > -50; }); updateStickman(); gambarStickman(); requestAnimationFrame(gameLoop); } // === INPUT === function aksi() { if (!gameJalan && !gameOver) { gameJalan=true; score=0; frame=0; kecepatan=4; rintangan=[]; timerR=0; sm.y=sm.groundY; sm.vy=0; sm.jumpCount=0; lompat(); } else if (gameOver) { gameOver=false; gameJalan=true; score=0; frame=0; kecepatan=4; rintangan=[]; timerR=0; sm.y=sm.groundY; sm.vy=0; sm.jumpCount=0; } else { lompat(); } } document.addEventListener('keydown', function(e) { if (e.code==='Space') { e.preventDefault(); aksi(); } }); canvas.addEventListener('click', aksi); gameLoop(); </script> </body> </html>
๐ Tantangan Kreatif untuk Siswa
Sudah selesai game dasarnya? Jangan berhenti di sini! Coba tantangan berikut untuk membuat game kalian makin seru dan unik:
โญ Level 1 โ Modifikasi Dasar
- Ganti warna stickman menjadi warna favorit kamu
- Buat kaktus lebih besar atau lebih kecil
- Tambahkan efek suara saat melompat menggunakan
AudioContext - Ubah background menjadi siang hari (langit biru)
โญโญ Level 2 โ Fitur Baru
- Tambahkan rintangan burung yang terbang di ketinggian berbeda
- Buat koin yang bisa dikumpulkan untuk bonus skor
- Tambahkan level system (tiap 500 poin naik level)
- Buat stickman bisa jongkok (tekan bawah/S) untuk hindari burung
โญโญโญ Level 3 โ Eksplorasi Mandiri
- Simpan high score ke
localStorageagar tidak hilang saat refresh - Tambahkan karakter berbeda yang bisa dipilih
- Buat animasi kaki stickman saat berlari
- Tambahkan mode multiplayer (2 pemain di keyboard yang sama)
๐ Kesimpulan & Refleksi
Selamat! Kalian sudah membuat game lengkap dari nol. Ini bukan hal kecil โ banyak developer profesional memulai perjalanan mereka persis seperti ini: membuat game sederhana di browser.
Konsep yang kalian pelajari hari ini โ loop, kondisi, object, array, event โ adalah fondasi dari semua program komputer. Sama persis yang dipakai di aplikasi besar seperti Gojek, Shopee, sampai game PC!
Di sesi berikutnya kita akan belajar menghubungkan game dengan AI menggunakan Kimi AI API โ bayangkan stickman yang bisa bicara dan bercerita! Sampai jumpa! ๐



