🎮 Membuat Game Memory Card Interaktif dengan HTML, CSS, dan JavaScript


🎮 Membuat Game Memory Card Interaktif dengan HTML, CSS, dan JavaScript

🎮 Apa Itu Game Memory Card?

Memory Card adalah game mencocokkan pasangan kartu yang mengasah ingatan. Dalam game ini, pemain akan:

  • Membalik dua kartu
  • Jika cocok, kartu akan tetap terbuka
  • Jika tidak cocok, kartu akan tertutup kembali

Kita akan buat game ini responsif, penuh warna, dan dilengkapi suara interaktif!


🔧 Fitur-Fitur Game

FiturPenjelasan
Mode GelapTampilan modern dan nyaman di mata
SkorBertambah jika menemukan pasangan yang cocok
TimerMenghitung waktu dari awal game
Efek SuaraFlip, match, dan wrong – membuat game lebih hidup
Restart GameTombol untuk memulai ulang kapan saja

🧩 Struktur Proyek

/memory-card-game
│
├── index.html
├── style.css
├── script.js
└── sounds/
    ├── flip.mp3
    ├── match.mp3
    └── wrong.mp3

🔗 Link Download Efek Suara Gratis

Letakkan file di dalam folder sounds/:

Klik kanan → “Save link as...” untuk menyimpannya.


💻 Kode Lengkap

index.html

<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Memory Card Game</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <div class="game-container">
    <h1>🎴 Memory Card Game</h1>
    <div class="info-bar">
      <span id="score">Skor: 0</span>
      <span id="timer">Waktu: 0 detik</span>
    </div>
    <div class="board" id="game-board"></div>
    <button id="reset">🔄 Reset Game</button>
  </div>

  <!-- Suara -->
  <audio id="sound-flip" src="sounds/flip.mp3"></audio>
  <audio id="sound-match" src="sounds/match.mp3"></audio>
  <audio id="sound-wrong" src="sounds/wrong.mp3"></audio>

  <script src="script.js"></script>
</body>
</html>

🎨 style.css

body {
  margin: 0;
  font-family: 'Segoe UI', sans-serif;
  background-color: #121212;
  color: #ffffff;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

.game-container {
  text-align: center;
  max-width: 600px;
}

h1 {
  margin-bottom: 20px;
  font-size: 2rem;
  color: #00e5ff;
}

.board {
  display: grid;
  grid-template-columns: repeat(4, 100px);
  gap: 15px;
  justify-content: center;
}

.card {
  width: 100px;
  height: 100px;
  background-color: #1e1e1e;
  border-radius: 12px;
  cursor: pointer;
  perspective: 1000px;
  position: relative;
  transition: transform 0.3s;
}

.card.flip .card-inner {
  transform: rotateY(180deg);
}

.card-inner {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s;
  position: relative;
}

.card-front, .card-back {
  width: 100%;
  height: 100%;
  position: absolute;
  border-radius: 12px;
  backface-visibility: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2rem;
}

.card-front {
  background-color: #333;
  color: #fff;
}

.card-back {
  transform: rotateY(180deg);
  color: #fff;
  font-weight: bold;
}

button#reset {
  margin-top: 20px;
  padding: 10px 20px;
  background: #00e5ff;
  color: #121212;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  cursor: pointer;
  transition: background 0.3s;
}

button#reset:hover {
  background: #00bcd4;
}

.info-bar {
  display: flex;
  justify-content: space-between;
  margin-bottom: 15px;
  font-size: 1.1rem;
  color: #ffeb3b;
  padding: 0 10px;
}

⚙️ script.js

const colors = [
  '#f44336', '#e91e63', '#9c27b0', '#3f51b5',
  '#03a9f4', '#009688', '#4caf50', '#ff9800'
];
const colorPairs = [...colors, ...colors];
const totalPairs = colors.length;

let firstCard = null;
let secondCard = null;
let lockBoard = false;
let score = 0;
let matchedPairs = 0;
let timer = 0;
let timerInterval;

const board = document.getElementById('game-board');
const scoreDisplay = document.getElementById('score');
const timerDisplay = document.getElementById('timer');
const soundFlip = document.getElementById('sound-flip');
const soundMatch = document.getElementById('sound-match');
const soundWrong = document.getElementById('sound-wrong');

function shuffle(array) {
  return array.sort(() => Math.random() - 0.5);
}

function createCard(color) {
  const card = document.createElement('div');
  card.classList.add('card');

  const inner = document.createElement('div');
  inner.classList.add('card-inner');

  const front = document.createElement('div');
  front.classList.add('card-front');
  front.textContent = '?';

  const back = document.createElement('div');
  back.classList.add('card-back');
  back.style.backgroundColor = color;
  back.textContent = '✔';

  inner.appendChild(front);
  inner.appendChild(back);
  card.appendChild(inner);

  card.dataset.color = color;
  card.addEventListener('click', handleFlip);

  return card;
}

function handleFlip() {
  if (lockBoard || this === firstCard || this.classList.contains('flip')) return;

  this.classList.add('flip');
  soundFlip.play();

  if (!firstCard) {
    firstCard = this;
    return;
  }

  secondCard = this;
  lockBoard = true;

  checkForMatch();
}

function checkForMatch() {
  const isMatch = firstCard.dataset.color === secondCard.dataset.color;

  if (isMatch) {
    handleMatch();
  } else {
    handleMismatch();
  }
}

function handleMatch() {
  soundMatch.play();
  score += 10;
  matchedPairs++;

  updateScore();
  firstCard.removeEventListener('click', handleFlip);
  secondCard.removeEventListener('click', handleFlip);

  resetTurn();

  if (matchedPairs === totalPairs) {
    clearInterval(timerInterval);
    setTimeout(() => {
      alert(`🎉 Kamu menang!\nSkor: ${score}\nWaktu: ${timer} detik`);
    }, 500);
  }
}

function handleMismatch() {
  soundWrong.play();
  setTimeout(() => {
    firstCard.classList.remove('flip');
    secondCard.classList.remove('flip');
    resetTurn();
  }, 800);
}

function resetTurn() {
  [firstCard, secondCard] = [null, null];
  lockBoard = false;
}

function updateScore() {
  scoreDisplay.textContent = `Skor: ${score}`;
}

function updateTimer() {
  timer++;
  timerDisplay.textContent = `Waktu: ${timer} detik`;
}

function startTimer() {
  clearInterval(timerInterval);
  timer = 0;
  timerDisplay.textContent = `Waktu: 0 detik`;
  timerInterval = setInterval(updateTimer, 1000);
}

function setupGame() {
  board.innerHTML = '';
  shuffle(colorPairs).forEach(color => {
    board.appendChild(createCard(color));
  });

  score = 0;
  matchedPairs = 0;
  updateScore();
  resetTurn();
  startTimer();
}

document.getElementById('reset').addEventListener('click', setupGame);

// Inisialisasi saat halaman dimuat
setupGame();

🎴 Efek Suara Membalik Kartu (Flip)

  1. Pixabay – Card Flipping Sound
    • Suara realistis membalik kartu.
  1. Orange Free Sounds – Card Flip
    • Suara kartu dibalik di atas meja.
  1. Audio.com – Card Flip by echopulsemystic
    • Suara efek membalik kartu yang halus.

✅ Efek Suara Pasangan Cocok (Match)

  1. Mixkit – Game Bonus
    • Suara bonus kemenangan yang menyenangkan.
  1. Pixabay – Game Bonus
    • Suara bonus kemenangan yang menyenangkan.

❌ Efek Suara Salah (Wrong)

  1. Pixabay – Wrong Answer
    • Suara buzzer jawaban salah.
  1. Orange Free Sounds – Incorrect Sound
    • Suara peringatan kesalahan.

🚀 Penutup

Dengan kode ini, kamu sudah bisa membuat game Memory Card interaktif yang seru dan bisa dimainkan siapa saja. Tambahkan ide-ide baru seperti level, soundtrack latar, atau leaderboard jika ingin mengembangkan lebih jauh.

Jika kamu ingin saya buatkan versi offline ZIP, GitHub deploy, atau export ke Android (WebView), tinggal bilang ya!

Komentar