🎮 Game Dev

Membangun Game 2D Pertama dengan JavaScript

🗓️ 28 Maret 2026 ⏱️ 12 menit baca 👤 Rhadzor

Membuat game adalah impian banyak developer. Rasanya magis ketika kode yang kita tulis tiba-tiba "hidup" dan bisa dimainkan. Kabar baiknya: kamu tidak perlu engine game canggih untuk memulai. Dengan HTML5 Canvas dan JavaScript murni, kita bisa membuat game 2D yang cukup kompleks.

Dalam tutorial ini, kita akan membuat game arcade sederhana: Space Shooter. Pesawat pemain bisa bergerak ke kiri-kanan, menembak peluru, dan musuh akan muncul dari atas layar. Siap? Let's code!

Mengapa HTML5 Canvas?

Canvas adalah elemen HTML yang menyediakan area gambar bitmap yang bisa dimanipulasi dengan JavaScript. Keunggulannya:

Langkah 1: Setup HTML dan Canvas

Pertama, buat file HTML dasar dengan elemen canvas. Ukuran canvas bisa disesuaikan, tapi untuk game mobile-friendly, 480x640 adalah rasio yang baik.

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Space Shooter</title>
    <style>
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: #0a0a1a;
        }
        canvas {
            border: 2px solid #00d9ff;
            box-shadow: 0 0 20px rgba(0, 217, 255, 0.5);
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="640"></canvas>
    <script src="game.js"></script>
</body>
</html>

Langkah 2: Game Loop Dasar

Setiap game membutuhkan game loop—siklus yang berjalan terus-menerus untuk mengupdate state game dan merender frame baru. Di JavaScript, kita gunakan requestAnimationFrame untuk loop yang smooth.

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Game state
const game = {
    isRunning: true,
    score: 0,
    lastTime: 0
};

// Main game loop
function gameLoop(timestamp) {
    if (!game.isRunning) return;
    
    // Calculate delta time
    const deltaTime = timestamp - game.lastTime;
    game.lastTime = timestamp;
    
    // Update game logic
    update(deltaTime);
    
    // Render
    render();
    
    // Next frame
    requestAnimationFrame(gameLoop);
}

function update(deltaTime) {
    // Update game objects here
}

function render() {
    // Clear canvas
    ctx.fillStyle = '#0a0a1a';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    // Draw game objects here
}

// Start game
requestAnimationFrame(gameLoop);

Mengapa requestAnimationFrame?

requestAnimationFrame sinkron dengan refresh rate monitor (biasanya 60fps), menghasilkan animasi yang jauh lebih halus daripada setInterval. Browser juga otomatis pause loop ketika tab tidak aktif—hemat baterai!

Langkah 3: Membuat Player

Sekarang kita buat objek player yang bisa bergerak. Untuk game ini, kita akan gunakan pendekatan OOP sederhana dengan class atau object literal.

const player = {
    x: canvas.width / 2,
    y: canvas.height - 80,
    width: 40,
    height: 40,
    speed: 5,
    color: '#00d9ff',
    
    update() {
        // Keyboard input
        if (keys.ArrowLeft && this.x > this.width/2) {
            this.x -= this.speed;
        }
        if (keys.ArrowRight && this.x < canvas.width - this.width/2) {
            this.x += this.speed;
        }
    },
    
    draw() {
        ctx.save();
        ctx.translate(this.x, this.y);
        
        // Draw spaceship (triangle)
        ctx.beginPath();
        ctx.moveTo(0, -this.height/2);
        ctx.lineTo(-this.width/2, this.height/2);
        ctx.lineTo(0, this.height/2 - 10);
        ctx.lineTo(this.width/2, this.height/2);
        ctx.closePath();
        
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 2;
        ctx.stroke();
        
        ctx.restore();
    }
};

// Input handling
const keys = {};
window.addEventListener('keydown', e => keys[e.key] = true);
window.addEventListener('keyup', e => keys[e.key] = false);

đź’ˇ Pro Tips: Input Handling

Langkah 4: Sistem Tembakan (Bullet System)

Game shooter tidak lengkap tanpa mekanisme tembak-menembak. Kita akan buat sistem bullet sederhana dengan array.

const bullets = [];
const bulletSpeed = 10;

function shoot() {
    bullets.push({
        x: player.x,
        y: player.y - player.height/2,
        width: 4,
        height: 12,
        speed: bulletSpeed,
        active: true
    });
}

// Spacebar to shoot
window.addEventListener('keydown', e => {
    if (e.code === 'Space') shoot();
});

function updateBullets() {
    bullets.forEach(bullet => {
        bullet.y -= bullet.speed;
        
        // Deactivate if off screen
        if (bullet.y < -bullet.height) {
            bullet.active = false;
        }
    });
    
    // Remove inactive bullets
    bullets = bullets.filter(b => b.active);
}

function drawBullets() {
    ctx.fillStyle = '#ff00ff';
    bullets.forEach(bullet => {
        ctx.fillRect(
            bullet.x - bullet.width/2,
            bullet.y,
            bullet.width,
            bullet.height
        );
    });
}

Langkah 5: Sistem Musuh dan Collision

Sekarang kita tambahkan musuh yang muncul dari atas dan collision detection sederhana.

const enemies = [];
let enemySpawnTimer = 0;
const enemySpawnInterval = 1000; // ms

function spawnEnemy() {
    enemies.push({
        x: Math.random() * (canvas.width - 40) + 20,
        y: -40,
        width: 35,
        height: 35,
        speed: 2 + Math.random() * 2,
        active: true
    });
}

function updateEnemies(deltaTime) {
    enemySpawnTimer += deltaTime;
    
    if (enemySpawnTimer > enemySpawnInterval) {
        spawnEnemy();
        enemySpawnTimer = 0;
    }
    
    enemies.forEach(enemy => {
        enemy.y += enemy.speed;
        
        if (enemy.y > canvas.height) {
            enemy.active = false;
        }
        
        // Check collision with bullets
        bullets.forEach(bullet => {
            if (bullet.active && checkCollision(bullet, enemy)) {
                bullet.active = false;
                enemy.active = false;
                game.score += 100;
            }
        });
    });
    
    enemies = enemies.filter(e => e.active);
}

function checkCollision(a, b) {
    return a.x < b.x + b.width/2 &&
           a.x + a.width > b.x - b.width/2 &&
           a.y < b.y + b.height/2 &&
           a.y + a.height > b.y - b.height/2;
}

Langkah 6: Polishing dan Game Feel

Game yang baik bukan hanya tentang mekanisme yang berfungsi, tapi juga game feel—sensasi dan feedback yang membuat pemain betah. Beberapa teknik sederhana:

1. Screen Shake saat Hit

let screenShake = 0;

function triggerShake(amount) {
    screenShake = amount;
}

function applyScreenShake() {
    if (screenShake > 0) {
        const dx = (Math.random() - 0.5) * screenShake;
        const dy = (Math.random() - 0.5) * screenShake;
        ctx.translate(dx, dy);
        screenShake *= 0.9; // Decay
        if (screenShake < 0.5) screenShake = 0;
    }
}

2. Particle Effects

const particles = [];

function createExplosion(x, y, color) {
    for (let i = 0; i < 10; i++) {
        particles.push({
            x: x,
            y: y,
            vx: (Math.random() - 0.5) * 8,
            vy: (Math.random() - 0.5) * 8,
            life: 1,
            color: color
        });
    }
}

function updateParticles() {
    particles.forEach(p => {
        p.x += p.vx;
        p.y += p.vy;
        p.life -= 0.02;
    });
    particles = particles.filter(p => p.life > 0);
}

Kesimpulan dan Next Steps

Selamat! Kamu sekarang punya game shooter 2D yang playable. Dari sini, kamu bisa mengembangkan lebih lanjut:

Game development adalah perjalanan panjang yang penuh pembelajaran. Setiap game yang kamu buat, sekecil apapun, akan mengajarkanmu sesuatu yang baru. Selamat berkarya!

🎮 Mainkan Game Eksklusif

Temukan lebih banyak game dan eksperimen interaktif di Studio Rhadzor. Dari prototype sederhana hingga game yang lebih polished.

Jelajahi Game →

Ada pertanyaan tentang game dev? Atau punya game yang ingin dishare? Kunjungi studio.rhadzor.id