Blog sayfan için ziyaretçileri sitende tutacak, tamamen HTML, CSS ve saf JavaScript (JS) ile yazılmış, şık ve bağımlılık yaratıcı bir oyun hazırladım: Hafıza Kartı Eşleştirme Oyunu (Memory Match).
Hafıza Eşleştirme Oyunu
Bu oyunda modern bir Glassmorphism (cam efekti) tasarımı kullandım. Sayfanın düzenini bozmaz ve responsive (mobil uyumlu) yapısıyla her ekranda harika görünür. Kodlarda harici bir görsel veya SVG icon paketi kullanmadım; her şey tamamen kodla ve saf metin emojileriyle tasarlandı.
Aşağıdaki kodu tek bir parça halinde Blogger'da ister yeni bir sayfada (HTML Görünümü modunda), ister bir HTML/JavaScript Gadget'ı içinde doğrudan kullanabilirsin.
<style>
/* Oyun Alanı Konteyneri ve Cam Efekti */
.game-wrapper {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1e1e2f 0%, #111119 100%);
padding: 30px 15px;
border-radius: 16px;
max-width: 600px;
margin: 20px auto;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
border: 1px solid rgba(255, 255, 255, 0.05);
text-align: center;
color: #ffffff;
}
.game-header h2 {
margin: 0 0 10px 0;
font-size: 24px;
letter-spacing: 1px;
background: linear-gradient(45deg, #ff416c, #ff4b2b);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Skor ve Sayaç Paneli */
.game-stats {
display: flex;
justify-content: space-around;
margin-bottom: 20px;
font-size: 16px;
font-weight: 600;
background: rgba(255, 255, 255, 0.03);
padding: 10px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.05);
}
.stat-box span {
color: #ff4b2b;
}
/* Kart Izgarası (Grid Layout) */
.game-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
perspective: 1000px;
margin-bottom: 20px;
}
/* Kart Yapısı ve 3D Döndürme Efektleri */
.memory-card {
height: 90px;
position: relative;
transform: scale(1);
transform-style: preserve-3d;
transition: transform 0.5s;
cursor: pointer;
border-radius: 8px;
}
.memory-card:active {
transform: scale(0.95);
transition: transform 0.2s;
}
.memory-card.flip {
transform: rotateY(180deg);
}
.card-front, .card-back {
width: 100%;
height: 100%;
position: absolute;
border-radius: 8px;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
/* Kartın Arka Yüzü (Kapalı Hali) */
.card-back {
background: linear-gradient(135deg, #232526 0%, #414345 100%);
border: 2px solid rgba(255, 255, 255, 0.1);
color: #ff4b2b;
font-weight: bold;
}
/* Kartın Ön Yüzü (Açık Hali) */
.card-front {
background: rgba(255, 255, 255, 0.07);
border: 2px solid rgba(255, 255, 255, 0.2);
transform: rotateY(180deg);
background-blend-mode: overlay;
}
/* Yeniden Başlat Butonu */
.restart-btn {
background: linear-gradient(45deg, #ff416c, #ff4b2b);
border: none;
color: white;
padding: 12px 28px;
font-size: 15px;
font-weight: 600;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 4px 15px rgba(255, 75, 43, 0.3);
transition: all 0.3s ease;
}
.restart-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(255, 75, 43, 0.5);
}
/* Mobil Uyumluluk Değişikliği */
@media (max-width: 480px) {
.memory-card {
height: 75px;
}
.card-front {
font-size: 26px;
}
}
</style>
</head>
<body>
<div class="game-wrapper">
<div class="game-header">
<h2>Hafıza Eşleştirme Oyunu</h2>
</div>
<div class="game-stats">
<div class="stat-box">Hamle: <span id="move-counter">0</span></div>
<div class="stat-box">Skor: <span id="score-counter">0</span></div>
</div>
<div class="game-grid" id="game-grid">
</div>
<button class="restart-btn" onclick="resetGame()">Yeniden Başlat</button>
</div>
<script>
// Oyun kartı sembolleri (Her birinden ikişer adet olacak)
const cardIcons = ['🎮', '🕹️', '⚔️', '🏆', '👑', '🚀', '👾', '🎯'];
let cards = [...cardIcons, ...cardIcons];
let hasFlippedCard = false;
let lockBoard = false;
let firstCard, secondCard;
let moves = 0;
let matches = 0;
const gridContainer = document.getElementById('game-grid');
const moveCounter = document.getElementById('move-counter');
const scoreCounter = document.getElementById('score-counter');
// Kartları Karıştırma Algoritması (Fisher-Yates)
function shuffle(array) {
let currentIndex = array.length, randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array;
}
// Oyunu Başlatma ve Kartları Izgaraya Dizme
function initGame() {
gridContainer.innerHTML = '';
const shuffledCards = shuffle(cards);
shuffledCards.forEach(icon => {
const cardElement = document.createElement('div');
cardElement.classList.add('memory-card');
cardElement.dataset.icon = icon;
cardElement.innerHTML = `
<div class="card-front">${icon}</div>
<div class="card-back">?</div>
`;
cardElement.addEventListener('click', flipCard);
gridContainer.appendChild(cardElement);
});
}
// Kartı Döndürme Fonksiyonu
function flipCard() {
if (lockBoard) return;
if (this === firstCard) return;
this.classList.add('flip');
if (!hasFlippedCard) {
// İlk kart seçimi
hasFlippedCard = true;
firstCard = this;
return;
}
// İkinci kart seçimi
secondCard = this;
checkForMatch();
}
// Eşleşme Kontrolü
function checkForMatch() {
moves++;
moveCounter.textContent = moves;
let isMatch = firstCard.dataset.icon === secondCard.dataset.icon;
isMatch ? disableCards() : unflipCards();
}
// Kartlar eşleştiyse kilitleri kaldır ve skoru arttır
function disableCards() {
firstCard.removeEventListener('click', flipCard);
secondCard.removeEventListener('click', flipCard);
matches++;
scoreCounter.textContent = matches * 10;
resetBoard();
// Oyun bittiyse tebrik et
if (matches === cardIcons.length) {
setTimeout(() => {
alert(`Tebrikler! Oyunu ${moves} hamlede bitirdiniz. Toplam Skor: ${matches * 10}`);
}, 500);
}
}
// Kartlar eşleşmediyse geri döndür
function unflipCards() {
lockBoard = true;
setTimeout(() => {
firstCard.classList.remove('flip');
secondCard.classList.remove('flip');
resetBoard();
}, 1000);
}
// Seçim değişkenlerini sıfırlama
function resetBoard() {
[hasFlippedCard, lockBoard] = [false, false];
[firstCard, secondCard] = [null, null];
}
// Oyunu Tamamen Sıfırlama
function resetGame() {
moves = 0;
matches = 0;
moveCounter.textContent = '0';
scoreCounter.textContent = '0';
resetBoard();
initGame();
}
// Sayfa yüklendiğinde oyunu başlat
document.addEventListener('DOMContentLoaded', initGame);
</script>
Özellikleri:
Görsel Temizlik: Şablonunun yüklenme hızını etkileyecek ağır harici kütüphaneler (
FontAwesomeveya ağır resim dosyaları gibi) içermez. Sadece saf CSS ve JS mimarisi kullanılmıştır.Tasarım: Siyah/Koyu gri tonlarında, modern oyun sitelerine uygun neon kırmızı/pembe geçişli dokunuşlara sahiptir.
Kullanıcı Deneyimi: Mobil uyumludur (Responsive). Dokunmatik ekranlarda kayma yapmaz.
Hiç yorum yok:
Yorum Gönder