文章目录[隐藏]
实战教学:为你的网站添加轻量级互动小游戏以提升用户参与度
引言:为什么网站需要互动小游戏?
在当今信息爆炸的互联网时代,用户注意力已成为最宝贵的资源。网站运营者面临着一个共同的挑战:如何在众多竞争者中脱颖而出,吸引并留住访问者?答案可能比你想象的更简单——互动性。
研究表明,具有互动元素的网站比静态网站的用户停留时间高出40%以上,页面浏览量增加35%,用户回访率提升25%。轻量级小游戏正是实现这种互动性的绝佳方式,它们不仅能够提升用户参与度,还能增强品牌记忆点,促进内容分享,甚至直接转化为商业价值。
WordPress作为全球最流行的内容管理系统,其强大的可扩展性为我们提供了实现这一目标的完美平台。通过代码二次开发,我们可以在不显著影响网站性能的前提下,为网站注入活力与趣味性。
第一部分:准备工作与环境搭建
1.1 选择合适的开发环境
在开始之前,我们需要确保拥有一个适合WordPress开发的环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
- WordPress安装:最新稳定版本(建议5.8+)
- 代码编辑器:VS Code、Sublime Text或PHPStorm
- 浏览器开发者工具:Chrome DevTools或Firefox Developer Edition
1.2 创建自定义插件框架
为了避免主题更新时丢失自定义功能,我们将创建一个独立的插件:
<?php
/**
* Plugin Name: 轻量级互动游戏套件
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress网站添加轻量级互动小游戏,提升用户参与度
* Version: 1.0.0
* Author: 你的名字
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('LIGHTGAMES_VERSION', '1.0.0');
define('LIGHTGAMES_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('LIGHTGAMES_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
function lightgames_init() {
// 加载文本域(用于国际化)
load_plugin_textdomain('lightgames', false, dirname(plugin_basename(__FILE__)) . '/languages');
// 注册短代码
add_shortcode('lightgame_quiz', 'lightgames_quiz_shortcode');
add_shortcode('lightgame_memory', 'lightgames_memory_shortcode');
add_shortcode('lightgame_spinwheel', 'lightgames_spinwheel_shortcode');
// 注册管理菜单
if (is_admin()) {
add_action('admin_menu', 'lightgames_admin_menu');
}
}
add_action('init', 'lightgames_init');
// 添加管理菜单
function lightgames_admin_menu() {
add_menu_page(
'互动游戏设置',
'互动游戏',
'manage_options',
'lightgames-settings',
'lightgames_settings_page',
'dashicons-games',
30
);
}
?>
第二部分:实现第一个小游戏——知识问答
2.1 设计游戏逻辑与数据结构
知识问答是最简单且有效的互动形式之一。我们将创建一个可配置的问答游戏:
// 在插件主文件中添加以下函数
function lightgames_quiz_shortcode($atts) {
// 解析短代码属性
$atts = shortcode_atts(array(
'category' => 'general',
'questions' => 5,
'time' => 30
), $atts, 'lightgame_quiz');
// 生成唯一ID用于游戏实例
$quiz_id = 'quiz_' . uniqid();
// 获取问题数据(实际应用中应从数据库或配置中获取)
$questions = lightgames_get_quiz_questions($atts['category'], $atts['questions']);
// 输出游戏HTML结构
ob_start();
?>
<div class="lightgame-quiz-container" id="<?php echo esc_attr($quiz_id); ?>" data-time="<?php echo esc_attr($atts['time']); ?>">
<div class="quiz-header">
<h3>知识挑战赛</h3>
<div class="quiz-stats">
<span class="score">得分: <strong>0</strong></span>
<span class="timer">时间: <strong><?php echo esc_html($atts['time']); ?></strong>秒</span>
<span class="progress">问题: <strong>1</strong>/<?php echo esc_html($atts['questions']); ?></span>
</div>
</div>
<div class="quiz-content">
<div class="question-container">
<!-- 问题将通过JavaScript动态加载 -->
</div>
<div class="options-container">
<!-- 选项将通过JavaScript动态加载 -->
</div>
<div class="quiz-controls">
<button class="quiz-btn prev-btn" disabled>上一题</button>
<button class="quiz-btn next-btn">下一题</button>
<button class="quiz-btn submit-btn">提交答案</button>
</div>
</div>
<div class="quiz-results" style="display:none;">
<h3>测验完成!</h3>
<div class="final-score">你的得分: <span>0</span>/<?php echo esc_html($atts['questions']); ?></div>
<div class="result-message"></div>
<button class="quiz-btn restart-btn">再试一次</button>
<button class="quiz-btn share-btn">分享结果</button>
</div>
</div>
<script type="application/json" class="quiz-questions-data">
<?php echo wp_json_encode($questions); ?>
</script>
<?php
return ob_get_clean();
}
// 获取问题数据的辅助函数
function lightgames_get_quiz_questions($category, $limit) {
// 这里应该是从数据库或配置文件中获取问题
// 为示例目的,我们返回静态数据
$questions = array(
array(
'question' => 'WordPress最初是什么类型的平台?',
'options' => array('博客平台', '电商系统', '社交网络', '论坛软件'),
'correct' => 0,
'explanation' => 'WordPress最初于2003年作为一个博客平台发布。'
),
array(
'question' => '以下哪个不是JavaScript框架?',
'options' => array('React', 'Vue', 'Laravel', 'Angular'),
'correct' => 2,
'explanation' => 'Laravel是PHP框架,不是JavaScript框架。'
),
// 可以添加更多问题...
);
// 随机选择指定数量的问题
shuffle($questions);
return array_slice($questions, 0, min($limit, count($questions)));
}
2.2 添加游戏样式与交互逻辑
创建CSS和JavaScript文件来实现游戏的视觉表现和交互:
/* lightgames.css */
.lightgame-quiz-container {
max-width: 800px;
margin: 20px auto;
border: 1px solid #e0e0e0;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
}
.quiz-header {
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
color: white;
padding: 20px;
text-align: center;
}
.quiz-header h3 {
margin: 0 0 15px 0;
font-size: 1.8em;
}
.quiz-stats {
display: flex;
justify-content: space-around;
font-size: 1.1em;
}
.quiz-stats strong {
font-weight: 700;
color: #ffde59;
}
.quiz-content {
padding: 25px;
background: #f9f9f9;
}
.question-container {
margin-bottom: 25px;
}
.question-container h4 {
font-size: 1.4em;
color: #333;
margin-bottom: 15px;
line-height: 1.4;
}
.options-container {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
margin-bottom: 25px;
}
@media (min-width: 600px) {
.options-container {
grid-template-columns: 1fr 1fr;
}
}
.quiz-option {
padding: 15px;
background: white;
border: 2px solid #e0e0e0;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
font-size: 1.1em;
text-align: left;
}
.quiz-option:hover {
border-color: #2575fc;
background: #f0f7ff;
}
.quiz-option.selected {
border-color: #4CAF50;
background: #e8f5e9;
}
.quiz-option.correct {
border-color: #4CAF50;
background: #e8f5e9;
}
.quiz-option.incorrect {
border-color: #f44336;
background: #ffebee;
}
.quiz-controls {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.quiz-btn {
padding: 12px 25px;
background: #2575fc;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 1em;
font-weight: 600;
transition: all 0.2s ease;
}
.quiz-btn:hover {
background: #1c65e0;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.quiz-btn:disabled {
background: #cccccc;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.quiz-results {
padding: 30px;
text-align: center;
background: white;
}
.final-score {
font-size: 2em;
margin: 20px 0;
color: #333;
}
.final-score span {
color: #4CAF50;
font-weight: 700;
}
.result-message {
font-size: 1.2em;
margin: 20px 0;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
}
// lightgames.js
document.addEventListener('DOMContentLoaded', function() {
// 初始化所有问答游戏
document.querySelectorAll('.lightgame-quiz-container').forEach(initQuizGame);
});
function initQuizGame(quizContainer) {
const questionsData = JSON.parse(quizContainer.querySelector('.quiz-questions-data').textContent);
const timeLimit = parseInt(quizContainer.getAttribute('data-time')) || 30;
let currentQuestion = 0;
let score = 0;
let userAnswers = [];
let timeLeft = timeLimit;
let timerInterval;
const questionEl = quizContainer.querySelector('.question-container');
const optionsEl = quizContainer.querySelector('.options-container');
const scoreEl = quizContainer.querySelector('.score strong');
const timerEl = quizContainer.querySelector('.timer strong');
const progressEl = quizContainer.querySelector('.progress strong');
const prevBtn = quizContainer.querySelector('.prev-btn');
const nextBtn = quizContainer.querySelector('.next-btn');
const submitBtn = quizContainer.querySelector('.submit-btn');
const resultsEl = quizContainer.querySelector('.quiz-results');
const finalScoreEl = quizContainer.querySelector('.final-score span');
const resultMessageEl = quizContainer.querySelector('.result-message');
const restartBtn = quizContainer.querySelector('.restart-btn');
const shareBtn = quizContainer.querySelector('.share-btn');
// 初始化游戏
function initGame() {
loadQuestion(currentQuestion);
startTimer();
updateControls();
}
// 加载问题
function loadQuestion(index) {
const question = questionsData[index];
// 更新问题文本
questionEl.innerHTML = `<h4>${index + 1}. ${question.question}</h4>`;
// 清空选项容器
optionsEl.innerHTML = '';
// 添加选项
question.options.forEach((option, i) => {
const optionEl = document.createElement('button');
optionEl.className = 'quiz-option';
if (userAnswers[index] === i) {
optionEl.classList.add('selected');
}
optionEl.textContent = option;
optionEl.addEventListener('click', () => selectOption(i));
optionsEl.appendChild(optionEl);
});
// 更新进度
progressEl.textContent = index + 1;
}
// 选择选项
function selectOption(optionIndex) {
// 移除之前的选择
optionsEl.querySelectorAll('.quiz-option').forEach(opt => {
opt.classList.remove('selected');
});
// 标记当前选择
optionsEl.children[optionIndex].classList.add('selected');
// 保存答案
userAnswers[currentQuestion] = optionIndex;
// 更新控制按钮状态
updateControls();
}
// 更新控制按钮状态
function updateControls() {
prevBtn.disabled = currentQuestion === 0;
nextBtn.disabled = currentQuestion === questionsData.length - 1;
submitBtn.disabled = userAnswers[currentQuestion] === undefined;
}
// 开始计时器
function startTimer() {
clearInterval(timerInterval);
timeLeft = timeLimit;
updateTimerDisplay();
timerInterval = setInterval(() => {
timeLeft--;
updateTimerDisplay();
if (timeLeft <= 0) {
clearInterval(timerInterval);
endGame();
}
}, 1000);
}
// 更新计时器显示
function updateTimerDisplay() {
timerEl.textContent = timeLeft;
// 时间不足时改变颜色
if (timeLeft <= 10) {
timerEl.style.color = '#f44336';
} else {
timerEl.style.color = '';
}
}
// 下一题
nextBtn.addEventListener('click', () => {
if (currentQuestion < questionsData.length - 1) {
currentQuestion++;
loadQuestion(currentQuestion);
updateControls();
}
});
// 上一题
prevBtn.addEventListener('click', () => {
if (currentQuestion > 0) {
currentQuestion--;
loadQuestion(currentQuestion);
updateControls();
}
});
// 提交答案
submitBtn.addEventListener('click', endGame);
// 结束游戏
function endGame() {
clearInterval(timerInterval);
// 计算得分
score = 0;
questionsData.forEach((question, index) => {
if (userAnswers[index] === question.correct) {
score++;
}
});
// 显示结果
quizContainer.querySelector('.quiz-content').style.display = 'none';
resultsEl.style.display = 'block';
finalScoreEl.textContent = `${score}/${questionsData.length}`;
// 根据得分显示不同消息
const percentage = (score / questionsData.length) * 100;
let message = '';
if (percentage >= 90) {
message = '太棒了!你简直是专家!';
} else if (percentage >= 70) {
message = '做得不错!你对这个主题有很好的了解。';
} else if (percentage >= 50) {
message = '还可以,但还有提升空间。';
} else {
message = '可能需要再复习一下这个主题。';
}
resultMessageEl.textContent = message;
// 更新得分显示
scoreEl.textContent = score;
}
// 重新开始
restartBtn.addEventListener('click', () => {
currentQuestion = 0;
score = 0;
userAnswers = [];
timeLeft = timeLimit;
quizContainer.querySelector('.quiz-content').style.display = 'block';
resultsEl.style.display = 'none';
initGame();
});
// 分享结果
shareBtn.addEventListener('click', () => {
const shareText = `我在知识挑战中获得了${score}/${questionsData.length}分!你也来试试吧!`;
if (navigator.share) {
navigator.share({
title: '知识挑战赛结果',
text: shareText,
url: window.location.href
});
} else {
// 备用方案:复制到剪贴板
navigator.clipboard.writeText(shareText + ' ' + window.location.href)
.then(() => alert('结果已复制到剪贴板!'));
}
});
// 开始游戏
initGame();
}
2.3 注册并加载资源文件
在插件初始化函数中添加资源加载代码:
// 在lightgames_init函数中添加
function lightgames_init() {
// ... 之前的代码 ...
// 注册前端资源
add_action('wp_enqueue_scripts', 'lightgames_enqueue_scripts');
}
// 加载前端资源
function lightgames_enqueue_scripts() {
// 仅在有短代码的页面加载资源
global $post;
if (is_a($post, 'WP_Post') &&
(has_shortcode($post->post_content, 'lightgame_quiz') ||
has_shortcode($post->post_content, 'lightgame_memory') ||
has_shortcode($post->post_content, 'lightgame_spinwheel'))) {
// 加载CSS
wp_enqueue_style(
'lightgames-style',
LIGHTGAMES_PLUGIN_URL . 'assets/css/lightgames.css',
array(),
LIGHTGAMES_VERSION
);
第三部分:实现第二个小游戏——记忆匹配
3.1 设计记忆匹配游戏逻辑
记忆匹配游戏是经典的互动游戏,能够有效提升用户的记忆力和参与度。我们将创建一个可配置的记忆卡片匹配游戏:
// 在插件主文件中添加记忆游戏短代码函数
function lightgames_memory_shortcode($atts) {
// 解析短代码属性
$atts = shortcode_atts(array(
'pairs' => 8,
'theme' => 'animals',
'difficulty' => 'medium'
), $atts, 'lightgame_memory');
// 根据难度设置时间限制
$time_limits = array(
'easy' => 120,
'medium' => 90,
'hard' => 60
);
$time_limit = isset($time_limits[$atts['difficulty']]) ?
$time_limits[$atts['difficulty']] : 90;
// 生成唯一ID
$game_id = 'memory_' . uniqid();
// 获取卡片数据
$cards = lightgames_get_memory_cards($atts['pairs'], $atts['theme']);
ob_start();
?>
<div class="lightgame-memory-container" id="<?php echo esc_attr($game_id); ?>"
data-pairs="<?php echo esc_attr($atts['pairs']); ?>"
data-time="<?php echo esc_attr($time_limit); ?>">
<div class="memory-header">
<h3>记忆大挑战</h3>
<div class="memory-stats">
<span class="moves">步数: <strong>0</strong></span>
<span class="timer">时间: <strong><?php echo esc_html($time_limit); ?></strong>秒</span>
<span class="matches">匹配: <strong>0</strong>/<?php echo esc_html($atts['pairs']); ?></span>
</div>
<div class="difficulty-badge difficulty-<?php echo esc_attr($atts['difficulty']); ?>">
<?php echo esc_html(ucfirst($atts['difficulty'])); ?> 难度
</div>
</div>
<div class="memory-grid-container">
<div class="memory-grid" style="grid-template-columns: repeat(<?php echo min(6, ceil(sqrt($atts['pairs'] * 2))); ?>, 1fr);">
<!-- 卡片将通过JavaScript动态生成 -->
</div>
</div>
<div class="memory-controls">
<button class="memory-btn start-btn">开始游戏</button>
<button class="memory-btn restart-btn" disabled>重新开始</button>
<button class="memory-btn hint-btn" disabled>提示</button>
</div>
<div class="memory-results" style="display:none;">
<h3>游戏完成!</h3>
<div class="stats-summary">
<div class="stat-item">
<span class="stat-label">用时:</span>
<span class="stat-value time-used">0</span>秒
</div>
<div class="stat-item">
<span class="stat-label">步数:</span>
<span class="stat-value total-moves">0</span>
</div>
<div class="stat-item">
<span class="stat-label">准确率:</span>
<span class="stat-value accuracy">100%</span>
</div>
<div class="stat-item">
<span class="stat-label">得分:</span>
<span class="stat-value final-score">0</span>
</div>
</div>
<div class="performance-rating"></div>
<div class="results-controls">
<button class="memory-btn play-again-btn">再玩一次</button>
<button class="memory-btn share-results-btn">分享成绩</button>
</div>
</div>
</div>
<script type="application/json" class="memory-cards-data">
<?php echo wp_json_encode($cards); ?>
</script>
<?php
return ob_get_clean();
}
// 获取记忆卡片数据的辅助函数
function lightgames_get_memory_cards($pairs, $theme) {
$pairs = min($pairs, 12); // 限制最大对数
// 不同主题的图标
$themes = array(
'animals' => array('🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮'),
'food' => array('🍎', '🍌', '🍇', '🍓', '🍒', '🍑', '🍍', '🥭', '🍉', '🍊', '🍋', '🥝'),
'sports' => array('⚽', '🏀', '🏈', '⚾', '🎾', '🏐', '🏉', '🎱', '🏓', '🏸', '🏒', '🏏'),
'flags' => array('🇨🇳', '🇺🇸', '🇬🇧', '🇯🇵', '🇰🇷', '🇫🇷', '🇩🇪', '🇮🇹', '🇪🇸', '🇷🇺', '🇧🇷', '🇦🇺'),
'vehicles' => array('🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐', '🚚', '🚛')
);
// 默认使用动物主题
$icons = isset($themes[$theme]) ? $themes[$theme] : $themes['animals'];
// 创建卡片对
$cards = array();
for ($i = 0; $i < $pairs; $i++) {
$icon = $icons[$i % count($icons)];
$cards[] = array(
'id' => $i * 2,
'value' => $icon,
'matched' => false
);
$cards[] = array(
'id' => $i * 2 + 1,
'value' => $icon,
'matched' => false
);
}
// 打乱顺序
shuffle($cards);
return $cards;
}
3.2 添加记忆游戏样式
在lightgames.css文件中添加记忆游戏的样式:
/* 记忆匹配游戏样式 */
.lightgame-memory-container {
max-width: 900px;
margin: 30px auto;
background: #fff;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
.memory-header {
background: linear-gradient(135deg, #ff6b6b 0%, #ffa726 100%);
color: white;
padding: 20px;
position: relative;
}
.memory-header h3 {
margin: 0 0 15px 0;
font-size: 1.8em;
text-align: center;
}
.memory-stats {
display: flex;
justify-content: space-around;
font-size: 1.1em;
margin-bottom: 10px;
}
.memory-stats strong {
font-weight: 700;
color: #fffacd;
}
.difficulty-badge {
position: absolute;
top: 20px;
right: 20px;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9em;
font-weight: 600;
}
.difficulty-easy {
background: #4CAF50;
color: white;
}
.difficulty-medium {
background: #FF9800;
color: white;
}
.difficulty-hard {
background: #F44336;
color: white;
}
.memory-grid-container {
padding: 25px;
background: #f5f7fa;
}
.memory-grid {
display: grid;
gap: 12px;
margin: 0 auto;
max-width: 800px;
}
.memory-card {
aspect-ratio: 1;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transform-style: preserve-3d;
transition: transform 0.6s;
font-size: 2.5em;
position: relative;
user-select: none;
}
.memory-card .card-front,
.memory-card .card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.memory-card .card-front {
background: white;
color: #333;
transform: rotateY(180deg);
}
.memory-card .card-back {
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
color: white;
}
.memory-card.flipped {
transform: rotateY(180deg);
}
.memory-card.matched {
transform: rotateY(180deg);
cursor: default;
}
.memory-card.matched .card-front {
background: #e8f5e9;
border: 3px solid #4CAF50;
}
.memory-card.hint {
animation: hint-pulse 1s ease-in-out;
}
@keyframes hint-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7); }
50% { box-shadow: 0 0 0 10px rgba(76, 175, 80, 0); }
}
.memory-controls {
padding: 20px;
background: white;
display: flex;
justify-content: center;
gap: 15px;
border-top: 1px solid #eee;
}
.memory-btn {
padding: 12px 25px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 1em;
font-weight: 600;
transition: all 0.3s ease;
}
.start-btn {
background: #4CAF50;
color: white;
}
.restart-btn {
background: #2196F3;
color: white;
}
.hint-btn {
background: #FF9800;
color: white;
}
.memory-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.memory-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.memory-results {
padding: 30px;
text-align: center;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.stats-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 20px;
margin: 30px 0;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.stat-item {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 3px 10px rgba(0,0,0,0.08);
}
.stat-label {
display: block;
color: #666;
font-size: 0.9em;
margin-bottom: 5px;
}
.stat-value {
font-size: 1.8em;
font-weight: 700;
color: #2575fc;
}
.performance-rating {
font-size: 1.3em;
margin: 20px 0;
padding: 15px;
background: white;
border-radius: 10px;
display: inline-block;
min-width: 300px;
}
.results-controls {
margin-top: 30px;
display: flex;
justify-content: center;
gap: 15px;
}
.play-again-btn {
background: #4CAF50;
color: white;
}
.share-results-btn {
background: #2196F3;
color: white;
}
3.3 添加记忆游戏JavaScript逻辑
在lightgames.js文件中添加记忆游戏的交互逻辑:
// 记忆匹配游戏逻辑
function initMemoryGame(gameContainer) {
const cardsData = JSON.parse(gameContainer.querySelector('.memory-cards-data').textContent);
const pairs = parseInt(gameContainer.getAttribute('data-pairs'));
const timeLimit = parseInt(gameContainer.getAttribute('data-time'));
let cards = [];
let flippedCards = [];
let matchedPairs = 0;
let moves = 0;
let timeLeft = timeLimit;
let gameStarted = false;
let gameTimer;
let canFlip = true;
// DOM元素
const gridEl = gameContainer.querySelector('.memory-grid');
const movesEl = gameContainer.querySelector('.moves strong');
const timerEl = gameContainer.querySelector('.timer strong');
const matchesEl = gameContainer.querySelector('.matches strong');
const startBtn = gameContainer.querySelector('.start-btn');
const restartBtn = gameContainer.querySelector('.restart-btn');
const hintBtn = gameContainer.querySelector('.hint-btn');
const resultsEl = gameContainer.querySelector('.memory-results');
const timeUsedEl = gameContainer.querySelector('.time-used');
const totalMovesEl = gameContainer.querySelector('.total-moves');
const accuracyEl = gameContainer.querySelector('.accuracy');
const finalScoreEl = gameContainer.querySelector('.final-score');
const performanceEl = gameContainer.querySelector('.performance-rating');
const playAgainBtn = gameContainer.querySelector('.play-again-btn');
const shareResultsBtn = gameContainer.querySelector('.share-results-btn');
// 初始化游戏板
function initGameBoard() {
gridEl.innerHTML = '';
cards = [...cardsData];
cards.forEach((cardData, index) => {
const card = document.createElement('div');
card.className = 'memory-card';
card.dataset.id = cardData.id;
card.dataset.value = cardData.value;
const cardFront = document.createElement('div');
cardFront.className = 'card-front';
cardFront.textContent = cardData.value;
const cardBack = document.createElement('div');
cardBack.className = 'card-back';
cardBack.textContent = '?';
card.appendChild(cardFront);
card.appendChild(cardBack);
card.addEventListener('click', () => flipCard(card));
gridEl.appendChild(card);
});
updateStats();
}
// 开始游戏
function startGame() {
if (gameStarted) return;
gameStarted = true;
startBtn.disabled = true;
restartBtn.disabled = false;
hintBtn.disabled = false;
// 开始计时
startTimer();
// 短暂显示所有卡片
showAllCardsBriefly();
}
// 显示所有卡片(游戏开始时)
function showAllCardsBriefly() {
const allCards = gridEl.querySelectorAll('.memory-card');
allCards.forEach(card => {
card.classList.add('flipped');
});
setTimeout(() => {
allCards.forEach(card => {
card.classList.remove('flipped');
});
canFlip = true;
}, 2000);
}
// 开始计时器
function startTimer() {
clearInterval(gameTimer);
timeLeft = timeLimit;
updateTimerDisplay();
gameTimer = setInterval(() => {
timeLeft--;
updateTimerDisplay();
if (timeLeft <= 0) {
endGame(false);
}
}, 1000);
}
// 更新计时器显示
function updateTimerDisplay() {
timerEl.textContent = timeLeft;
if (timeLeft <= 10) {
timerEl.style.color = '#f44336';
timerEl.style.animation = timeLeft <= 5 ? 'pulse 0.5s infinite' : 'none';
} else {
timerEl.style.color = '';
timerEl.style.animation = '';
}
}
// 翻转卡片
function flipCard(card) {
if (!canFlip || !gameStarted) return;
if (card.classList.contains('flipped') || card.classList.contains('matched')) return;
if (flippedCards.length >= 2) return;
card.classList.add('flipped');
flippedCards.push(card);
if (flippedCards.length === 2) {
moves++;
movesEl.textContent = moves;
canFlip = false;
// 检查是否匹配
const card1 = flippedCards[0];
const card2 = flippedCards[1];
if (card1.dataset.value === card2.dataset.value) {
// 匹配成功
setTimeout(() => {
card1.classList.add('matched');
card2.classList.add('matched');
flippedCards = [];
matchedPairs++;
matchesEl.textContent = matchedPairs;
canFlip = true;
// 检查游戏是否完成
if (matchedPairs === pairs) {
endGame(true);
}
}, 500);
} else {
// 不匹配,翻回去
setTimeout(() => {
card1.classList.remove('flipped');
card2.classList.remove('flipped');
flippedCards = [];
canFlip = true;
}, 1000);
}
}
}
// 提示功能
function provideHint() {
if (!gameStarted || flippedCards.length > 0) return;
// 找到两个未匹配的相同卡片
