儿童趣味记忆配对游戏
将设计一个适合6岁以下儿童的记忆配对游戏,包含可爱的动物图案、简单操作和丰富的视觉反馈。
设计思路
- 使用明亮友好的色彩方案
- 采用大尺寸卡片方便儿童点击
- 添加成功动画和音效反馈
- 实现简单的游戏进度指示
- 添加游戏完成庆祝动画
下面是完整的实现代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>儿童记忆配对游戏</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Comic Sans MS', 'Marker Felt', '华文圆体', cursive;
}
body {
background: linear-gradient(135deg, #6ecbf5 0%, #e4f5fc 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
overflow-x: hidden;
}
header {
text-align: center;
margin: 15px 0 30px;
width: 100%;
}
h1 {
color: #ff6b6b;
font-size: 2.8rem;
text-shadow: 3px 3px 0 #ffd166;
margin-bottom: 10px;
letter-spacing: 1px;
}
.subtitle {
color: #4a4a9c;
font-size: 1.5rem;
margin-bottom: 20px;
}
.game-container {
display: flex;
flex-direction: column;
align-items: center;
max-width: 800px;
width: 100%;
}
.stats {
display: flex;
justify-content: space-around;
width: 100%;
background: rgba(255, 255, 255, 0.7);
padding: 15px;
border-radius: 20px;
margin-bottom: 25px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.stat-box {
text-align: center;
padding: 10px 20px;
background: #ffd166;
border-radius: 15px;
min-width: 120px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.stat-value {
font-size: 2.2rem;
font-weight: bold;
color: #ef476f;
}
.stat-label {
font-size: 1.2rem;
color: #4a4a9c;
}
.game-board {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
width: 100%;
max-width: 600px;
margin: 0 auto 30px;
perspective: 1000px;
}
.card {
height: 120px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
cursor: pointer;
border-radius: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.card.flipped {
transform: rotateY(180deg);
}
.card.matched .card-front {
background: #06d6a0;
}
.card-face {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
display: flex;
justify-content: center;
align-items: center;
border-radius: 20px;
overflow: hidden;
}
.card-back {
background: radial-gradient(circle, #ff6b6b, #ef476f);
transform: rotateY(0deg);
}
.card-back::before {
content: "?";
font-size: 4rem;
color: white;
text-shadow: 3px 3px 0 rgba(0, 0, 0, 0.2);
}
.card-front {
background: white;
transform: rotateY(180deg);
padding: 10px;
}
.card-front img {
width: 80%;
height: auto;
max-height: 90px;
object-fit: contain;
}
.controls {
display: flex;
gap: 20px;
margin-top: 15px;
}
button {
background: #ffd166;
border: none;
padding: 15px 30px;
font-size: 1.4rem;
border-radius: 50px;
cursor: pointer;
color: #4a4a9c;
font-weight: bold;
box-shadow: 0 6px 0 #ffb700;
transition: all 0.2s;
min-width: 180px;
}
button:hover {
background: #ffd880;
transform: translateY(2px);
box-shadow: 0 4px 0 #ffb700;
}
button:active {
transform: translateY(6px);
box-shadow: none;
}
.instructions {
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 20px;
margin: 30px 0;
width: 100%;
max-width: 600px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.instructions h2 {
color: #118ab2;
text-align: center;
margin-bottom: 15px;
font-size: 1.8rem;
}
.instructions ol {
padding-left: 25px;
font-size: 1.3rem;
line-height: 1.6;
color: #4a4a9c;
}
.instructions li {
margin-bottom: 12px;
}
.celebration {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 100;
opacity: 0;
pointer-events: none;
transition: opacity 0.5s;
}
.celebration.show {
opacity: 1;
pointer-events: all;
}
.celebration-content {
background: white;
padding: 40px;
border-radius: 30px;
text-align: center;
max-width: 90%;
box-shadow: 0 0 50px rgba(255, 255, 255, 0.5);
}
.celebration h2 {
color: #ef476f;
font-size: 3.5rem;
margin-bottom: 20px;
}
.celebration p {
font-size: 2rem;
color: #4a4a9c;
margin-bottom: 30px;
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background: #ffd166;
animation: fall linear forwards;
}
@keyframes fall {
to {
transform: translateY(100vh) rotate(360deg);
}
}
@media (max-width: 600px) {
.game-board {
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.card {
height: 100px;
}
h1 {
font-size: 2.2rem;
}
.subtitle {
font-size: 1.2rem;
}
button {
font-size: 1.2rem;
padding: 12px 20px;
min-width: 140px;
}
}
</style>
</head>
<body>
<header>
<h1>动物记忆配对游戏</h1>
<div class="subtitle">找出所有相同的动物朋友!</div>
</header>
<div class="game-container">
<div class="stats">
<div class="stat-box">
<div class="stat-value" id="moves">0</div>
<div class="stat-label">步数</div>
</div>
<div class="stat-box">
<div class="stat-value" id="pairs">0</div>
<div class="stat-label">已配对</div>
</div>
<div class="stat-box">
<div class="stat-value" id="timer">0</div>
<div class="stat-label">秒</div>
</div>
</div>
<div class="game-board" id="game-board"></div>
<div class="controls">
<button id="restart-btn">重新开始</button>
<button id="help-btn">游戏说明</button>
</div>
</div>
<div class="instructions">
<h2>游戏玩法</h2>
<ol>
<li>点击卡片,看看是什么动物</li>
<li>再点击另一张卡片,尝试找到相同的动物</li>
<li>如果两张卡片相同,它们会保持翻开</li>
<li>如果两张卡片不同,它们会翻回去</li>
<li>记住动物的位置,尽快找到所有配对!</li>
</ol>
</div>
<div class="celebration" id="celebration">
<div class="celebration-content">
<h2>太棒了!</h2>
<p>你找到了所有动物朋友!</p>
<button id="play-again">再玩一次</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 游戏配置
const animals = ['🐶', '🐱', '🐰', '🐻', '🐯', '🦁', '🐮', '🐷'];
const cardValues = [...animals, ...animals];
let flippedCards = [];
let matchedPairs = 0;
let moves = 0;
let timer = 0;
let timerInterval;
let gameStarted = false;
const gameBoard = document.getElementById('game-board');
const movesElement = document.getElementById('moves');
const pairsElement = document.getElementById('pairs');
const timerElement = document.getElementById('timer');
const restartBtn = document.getElementById('restart-btn');
const playAgainBtn = document.getElementById('play-again');
const celebration = document.getElementById('celebration');
// 初始化游戏
function initGame() {
gameBoard.innerHTML = '';
flippedCards = [];
matchedPairs = 0;
moves = 0;
timer = 0;
gameStarted = false;
movesElement.textContent = moves;
pairsElement.textContent = matchedPairs;
timerElement.textContent = timer;
clearInterval(timerInterval);
// 洗牌
const shuffledCards = [...cardValues].sort(() => Math.random() - 0.5);
// 创建卡片
shuffledCards.forEach((value, index) => {
const card = document.createElement('div');
card.classList.add('card');
card.dataset.value = value;
card.innerHTML = `
<div class="card-face card-back"></div>
<div class="card-face card-front">
<div style="font-size: 4rem;">${value}</div>
</div>
`;
card.addEventListener('click', flipCard);
gameBoard.appendChild(card);
});
}
// 翻牌函数
function flipCard() {
// 如果游戏未开始,启动计时器
if (!gameStarted) {
startTimer();
gameStarted = true;
}
// 如果已经翻开了两张牌或这张牌已经匹配,则返回
if (flippedCards.length === 2 ||
this.classList.contains('flipped') ||
this.classList.contains('matched')) {
return;
}
// 翻牌
this.classList.add('flipped');
flippedCards.push(this);
// 播放音效
playSound('flip');
// 如果翻开了两张牌,检查是否匹配
if (flippedCards.length === 2) {
moves++;
movesElement.textContent = moves;
const card1 = flippedCards[0];
const card2 = flippedCards[1];
if (card1.dataset.value === card2.dataset.value) {
// 匹配成功
card1.classList.add('matched');
card2.classList.add('matched');
matchedPairs++;
pairsElement.textContent = matchedPairs;
playSound('match');
flippedCards = [];
// 检查游戏是否结束
if (matchedPairs === animals.length) {
endGame();
}
} else {
// 匹配失败
setTimeout(() => {
card1.classList.remove('flipped');
card2.classList.remove('flipped');
flippedCards = [];
}, 1000);
}
}
}
// 开始计时器
function startTimer() {
clearInterval(timerInterval);
timerInterval = setInterval(() => {
timer++;
timerElement.textContent = timer;
}, 1000);
}
// 结束游戏
function endGame() {
clearInterval(timerInterval);
// 创建庆祝效果
createConfetti();
// 显示庆祝画面
setTimeout(() => {
celebration.classList.add('show');
}, 1000);
}
// 创建五彩纸屑效果
function createConfetti() {
const colors = ['#ff6b6b', '#ffd166', '#06d6a0', '#118ab2', '#ef476f'];
for (let i = 0; i < 150; i++) {
const confetti = document.createElement('div');
confetti.classList.add('confetti');
// 随机位置
const posX = Math.random() * window.innerWidth;
const posY = Math.random() * -100;
// 随机大小
const size = Math.random() * 10 + 5;
// 随机颜色
const color = colors[Math.floor(Math.random() * colors.length)];
// 随机动画时长
const duration = Math.random() * 3 + 2;
// 随机延迟
const delay = Math.random() * 2;
confetti.style.left = `${posX}px`;
confetti.style.top = `${posY}px`;
confetti.style.width = `${size}px`;
confetti.style.height = `${size}px`;
confetti.style.backgroundColor = color;
confetti.style.animation = `fall ${duration}s linear ${delay}s forwards`;
document.body.appendChild(confetti);
// 动画结束后移除元素
setTimeout(() => {
confetti.remove();
}, (duration + delay) * 1000);
}
playSound('win');
}
// 播放音效
function playSound(type) {
try {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
let oscillator = audioContext.createOscillator();
let gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// 根据不同事件设置不同音效
switch(type) {
case 'flip':
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
break;
case 'match':
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime); // E5
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
break;
case 'win':
// 播放一个简单的胜利旋律
const melody = [
{note: 784.00, duration: 0.2}, // G5
{note: 880.00, duration: 0.2}, // A5
{note: 987.77, duration: 0.4} // B5
];
let time = audioContext.currentTime;
melody.forEach(tone => {
let oscillator = audioContext.createOscillator();
let gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = 'triangle';
oscillator.frequency.setValueAtTime(tone.note, time);
gainNode.gain.setValueAtTime(0.3, time);
gainNode.gain.exponentialRampToValueAtTime(0.01, time + tone.duration);
oscillator.start(time);
oscillator.stop(time + tone.duration);
time += tone.duration;
});
return;
}
oscillator.start();
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
oscillator.stop(audioContext.currentTime + 0.3);
} catch(e) {
console.log("音频播放失败:", e);
}
}
// 事件监听器
restartBtn.addEventListener('click', initGame);
playAgainBtn.addEventListener('click', () => {
celebration.classList.remove('show');
initGame();
});
// 初始游戏
initGame();
});
</script>
</body>
</html>
游戏特点
儿童友好设计:
- 使用明亮鲜艳的色彩和圆角设计
- 大尺寸卡片方便儿童点击
- 可爱的动物表情符号作为配对元素
游戏机制:
- 记忆配对核心玩法
- 实时显示步数、配对数量和用时
- 成功匹配的卡片会有视觉反馈
交互反馈:
- 卡片翻转动画
- 匹配成功时的音效
- 游戏完成时的庆祝动画和五彩纸屑效果
教育价值:
- 锻炼记忆力和观察力
- 培养专注力和耐心
- 学习识别不同动物
响应式设计:
- 适应不同屏幕尺寸
- 在手机和平板上都能良好显示
这个游戏不需要任何外部依赖,可以直接在浏览器中打开运行,非常适合6岁以下儿童使用。游戏操作简单直观,界面友好,能够提供愉快的游戏体验。