Files
RGKT/rg-09112127/html/play/识数小精灵.html
2025-10-10 19:44:14 +08:00

1436 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>数字乐园</title>
<!-- 引入后端集成脚本 -->
<script src="../../js/apiService.js"></script>
<script src="../../js/dataManager.js"></script>
<script src="../../js/userManager.js"></script>
<script src="../../js/accessTracker.js"></script>
<script src="../../js/gameTracker.js"></script>
<script src="../../js/gameDataLogger.js"></script>
<style>
/* 全局样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Comic Neue", cursive;
background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);
height: 100vh;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
/* 气球装饰 */
.balloon {
position: absolute;
width: 80px;
height: 100px;
background: radial-gradient(circle at 30% 30%, #ff9a9e, #fad0c4);
border-radius: 50%;
box-shadow: inset -10px -10px 10px rgba(0, 0, 0, 0.1);
animation: float 15s infinite ease-in-out;
z-index: -1;
}
.balloon::after {
content: "";
position: absolute;
bottom: -15px;
left: 50%;
width: 2px;
height: 30px;
background: #ff9a9e;
transform: translateX(-50%);
}
/* 鲜花装饰 */
.flower {
position: absolute;
width: 60px;
height: 60px;
background: radial-gradient(
circle at center,
#ffe66d 30%,
#ff9a9e 100%
);
border-radius: 50%;
animation: sway 8s infinite ease-in-out;
z-index: -1;
}
.flower::before {
content: "";
position: absolute;
bottom: -20px;
left: 50%;
width: 3px;
height: 40px;
background: #74b9ff;
transform: translateX(-50%);
}
@keyframes float {
0%,
100% {
transform: translateY(0) rotate(0deg);
}
50% {
transform: translateY(-50px) rotate(5deg);
}
}
@keyframes sway {
0%,
100% {
transform: translateX(0) rotate(0deg);
}
50% {
transform: translateX(20px) rotate(10deg);
}
}
/* 主容器样式 */
.main-container {
width: 90%;
max-width: 1000px;
height: 90vh;
position: relative;
overflow: hidden;
background: rgba(255, 255, 255, 0.8);
border-radius: 40px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
border: 8px solid #ffe66d;
transition: all 0.3s ease;
}
.main-container:hover {
transform: scale(1.02);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
}
/* 开始菜单样式 */
.start-menu {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.9);
border-radius: 30px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
z-index: 10;
transition: all 0.5s ease;
}
.start-title {
font-size: 5rem;
color: #ff6b6b;
text-shadow: 5px 5px 0 #ffe66d;
margin-bottom: 50px;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%,
100% {
transform: translateY(0);
}
25% {
transform: translateY(-2px);
animation-timing-function: ease-in-out;
}
50% {
transform: translateY(0);
}
75% {
transform: translateY(2px);
animation-timing-function: ease-in-out;
}
}
.start-button {
width: 200px;
height: 200px;
border-radius: 50%;
background: linear-gradient(145deg, #ff9a9e, #ff6b6b);
border: 5px solid #ffe66d;
color: white;
font-size: 2.5rem;
cursor: pointer;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3),
inset 0 0 20px rgba(255, 255, 255, 0.5);
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
transition: all 0.3s;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
.start-button:hover {
transform: scale(1.1);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.4);
}
.start-button::before {
content: "";
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(
circle,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0) 70%
);
transform: scale(0);
transition: transform 0.5s;
}
.start-button:active::before {
transform: scale(1);
}
/* 游戏界面样式 */
.game-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
flex-direction: column;
justify-content: flex-start;
align-items: center;
background: rgba(255, 255, 255, 0.9);
border-radius: 30px;
z-index: 5;
padding: 20px;
box-sizing: border-box;
}
.game-header {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 0 10px;
}
.progress-container {
width: 60%;
height: 30px;
background-color: #f1f1f1;
border-radius: 15px;
overflow: hidden;
}
.progress-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #74b9ff, #0984e3);
border-radius: 15px;
transition: width 0.5s;
}
.back-button {
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(145deg, #ff7675, #d63031);
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s;
}
.back-button:hover {
transform: scale(1.1);
}
.game-content {
width: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
padding: 10px 0;
}
.game-image {
width: 90%;
max-width: 500px;
height: auto;
max-height: 300px;
object-fit: contain;
margin: 20px 0;
border-radius: 20px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
transition: all 0.3s;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
.number-options {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
width: 100%;
max-width: 600px;
margin: 20px 0;
}
.number-btn {
width: 100px;
height: 100px;
border-radius: 50%;
color: white;
font-size: 3rem;
border: none;
cursor: pointer;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
transition: all 0.3s;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
}
.number-btn[data-number="1"] {
background: linear-gradient(145deg, #74b9ff, #0984e3);
}
.number-btn[data-number="2"] {
background: linear-gradient(145deg, #ff7675, #d63031);
}
.number-btn[data-number="3"] {
background: linear-gradient(145deg, #55efc4, #00b894);
}
.number-btn[data-number="4"] {
background: linear-gradient(145deg, #a29bfe, #6c5ce7);
}
.number-btn[data-number="5"] {
background: linear-gradient(145deg, #ffeaa7, #fdcb6e);
}
.number-btn:hover {
transform: scale(1.1);
box-shadow: 0 15px 25px rgba(0, 0, 0, 0.3);
}
.number-btn::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 5px;
height: 5px;
background: rgba(255, 255, 255, 0.5);
opacity: 0;
border-radius: 100%;
transform: scale(1, 1) translate(-50%, -50%);
transform-origin: 50% 50%;
}
.number-btn:focus:not(:active)::after {
animation: ripple 1s ease-out;
}
@keyframes ripple {
0% {
transform: scale(0, 0);
opacity: 0.5;
}
100% {
transform: scale(20, 20);
opacity: 0;
}
}
.feedback {
height: 80px;
width: 80px;
margin-top: 20px;
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
opacity: 0;
transition: all 0.3s;
}
.correct {
color: #00b894;
animation: correct-feedback 0.5s;
}
.incorrect {
color: #d63031;
animation: incorrect-feedback 0.5s;
}
@keyframes correct-feedback {
0% {
transform: scale(0);
opacity: 0;
}
50% {
transform: scale(1.5);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes incorrect-feedback {
0%,
100% {
transform: translateX(0);
}
20%,
60% {
transform: translateX(-10px);
}
40%,
80% {
transform: translateX(10px);
}
}
/* 胜利界面样式 */
.victory-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.8);
border-radius: 30px;
z-index: 20;
}
.victory-content {
text-align: center;
color: white;
}
.victory-icon {
font-size: 10rem;
margin-bottom: 30px;
color: #ffe66d;
text-shadow: 0 0 20px #ff9f43;
animation: victory-glow 2s infinite;
}
@keyframes victory-glow {
0%,
100% {
transform: scale(1);
text-shadow: 0 0 20px #ff9f43;
}
50% {
transform: scale(1.2);
text-shadow: 0 0 40px #ff9f43;
}
}
.victory-button {
width: 150px;
height: 150px;
border-radius: 50%;
background: linear-gradient(145deg, #00b894, #55efc4);
border: none;
color: white;
font-size: 2rem;
cursor: pointer;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
margin-top: 50px;
transition: all 0.3s;
}
.victory-button:hover {
transform: scale(1.1);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
/* 粒子特效 */
.particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 30;
}
.particle {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #ffe66d;
opacity: 0;
}
/* 音量开关按钮样式 */
.sound-toggle {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(145deg, #74b9ff, #0984e3);
border: 3px solid #ffe66d;
color: white;
font-size: 2.5rem;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
transition: all 0.3s;
}
.sound-toggle:hover {
transform: scale(1.1);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
}
/* 响应式设计 */
@media (max-width: 768px) {
.start-title {
font-size: 3rem;
}
.start-button {
width: 150px;
height: 150px;
}
.game-image {
width: 90%;
height: auto;
max-height: 250px;
}
.number-btn {
width: 70px;
height: 70px;
font-size: 2rem;
}
.sound-toggle {
width: 60px;
height: 60px;
font-size: 2rem;
}
}
</style>
<script>
// 添加随机气球
function createBalloons() {
const colors = ["#ff9a9e", "#74b9ff", "#ffe66d", "#a29bfe", "#55efc4"];
for (let i = 0; i < 8; i++) {
const balloon = document.createElement("div");
balloon.className = "balloon";
balloon.style.left = Math.random() * 100 + "%";
balloon.style.top = Math.random() * 100 + "%";
balloon.style.width = Math.random() * 40 + 60 + "px";
balloon.style.height = Math.random() * 60 + 80 + "px";
balloon.style.background = `radial-gradient(circle at 30% 30%, ${
colors[i % colors.length]
}, ${colors[(i + 1) % colors.length]})`;
balloon.style.animationDuration = Math.random() * 10 + 10 + "s";
document.body.appendChild(balloon);
}
}
// 添加随机鲜花
function createFlowers() {
const colors = ["#ffe66d", "#ff9a9e", "#74b9ff", "#a29bfe", "#55efc4"];
for (let i = 0; i < 6; i++) {
const flower = document.createElement("div");
flower.className = "flower";
flower.style.left = Math.random() * 100 + "%";
flower.style.top = Math.random() * 100 + "%";
flower.style.width = Math.random() * 30 + 50 + "px";
flower.style.height = Math.random() * 30 + 50 + "px";
flower.style.background = `radial-gradient(circle at center, ${
colors[i % colors.length]
} 30%, ${colors[(i + 2) % colors.length]} 100%)`;
flower.style.animationDuration = Math.random() * 5 + 8 + "s";
document.body.appendChild(flower);
}
}
// 页面加载后创建装饰
window.onload = function () {
createBalloons();
createFlowers();
};
</script>
</head>
<body>
<audio src="" controls id="audioPlayer" style="display: none"></audio>
<audio
src="MP3/背景音1.mp3"
id="bgMusic"
loop
style="display: none"
></audio>
<div class="main-container">
<!-- 开始菜单 -->
<div class="start-menu">
<h1 class="start-title">数字乐园</h1>
<div
style="
display: flex;
justify-content: center;
gap: 20px;
width: 100%;
margin-top: 20px;
"
>
<button
class="start-button"
id="numberButton"
style="display: flex; flex-direction: column; align-items: center"
>
<span style="font-size: 3rem; margin-bottom: 10px">🔢</span>
<span style="font-size: 1.2rem">数字学习</span>
</button>
<button
class="start-button"
id="audioGameButton"
style="display: flex; flex-direction: column; align-items: center"
>
<span style="font-size: 3rem; margin-bottom: 10px">👂</span>
<span style="font-size: 1.2rem">听音识数</span>
</button>
<button
class="start-button"
id="pictureGameButton"
style="display: flex; flex-direction: column; align-items: center"
>
<span style="font-size: 3rem; margin-bottom: 10px">👀</span>
<span style="font-size: 1.2rem">看图识数</span>
</button>
</div>
<button class="sound-toggle" id="soundToggle" style="margin-top: 30px">
<span class="sound-icon">🔊</span>
</button>
</div>
<!-- 游戏界面 -->
<div class="game-screen" id="gameScreen">
<div class="game-header">
<button class="back-button" id="backButton"></button>
<div class="progress-container">
<div class="progress-bar" id="progressBar"></div>
</div>
</div>
<div class="game-content">
<img
class="game-image"
id="gameImage"
src="img/1/1.png"
alt="数字图片"
/>
<div class="number-options">
<button class="number-btn" data-number="1">1</button>
<button class="number-btn" data-number="2">2</button>
<button class="number-btn" data-number="3">3</button>
<button class="number-btn" data-number="4">4</button>
<button class="number-btn" data-number="5">5</button>
</div>
<div class="feedback" id="feedback"></div>
</div>
</div>
<!-- 胜利界面 -->
<div class="victory-screen" id="victoryScreen">
<div class="victory-content">
<div class="victory-icon"></div>
<button class="victory-button" id="victoryButton"></button>
</div>
</div>
<!-- 粒子特效容器 -->
<div class="particles" id="particles"></div>
</div>
<script>
async function speak2(text, vcn = "x4_lingyouyou", speed = 50) {
try {
const params = new URLSearchParams();
params.append("text", text);
params.append("vcn", vcn);
params.append("speed", speed);
const response = await fetch(
"http://rgclass.iflysse.com:8200/text2audio",
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
}
);
if (!response.ok) throw new Error(`请求失败: ${response.status}`);
const audioPath = await response.text();
const audioUrl = `http://rgclass.iflysse.com:8200${audioPath.trim()}`;
const audioPlayer = document.querySelector("#audioPlayer");
audioPlayer.src = audioUrl;
setTimeout(() => {
audioPlayer.load();
audioPlayer.play();
}, 200);
} catch (error) {
console.error("请求出错:", error);
}
}
// 游戏数据
const questions = [
{ image: "img/1/1.png", answer: 1 },
{ image: "img/2/1.png", answer: 2 },
{ image: "img/3/1.png", answer: 3 },
{ image: "img/4/1.png", answer: 4 },
{ image: "img/5/1.png", answer: 5 },
{ image: "img/1/2.png", answer: 1 },
{ image: "img/2/2.png", answer: 2 },
{ image: "img/3/2.png", answer: 3 },
{ image: "img/4/2.png", answer: 4 },
{ image: "img/5/2.png", answer: 5 },
];
// 游戏模式
let gameMode = "picture"; // 'picture'或'audio'
// 游戏状态
let currentQuestion = 0;
let correctAnswers = 0;
const totalQuestions = 5; // 需要答对的题目数量
let gameStarted = false;
let timer; // 倒计时计时器
// DOM元素
const startMenu = document.querySelector(".start-menu");
const gameScreen = document.getElementById("gameScreen");
const victoryScreen = document.getElementById("victoryScreen");
const startButton = document.getElementById("startButton");
const backButton = document.getElementById("backButton");
const victoryButton = document.getElementById("victoryButton");
const gameImage = document.getElementById("gameImage");
const feedback = document.getElementById("feedback");
const progressBar = document.getElementById("progressBar");
const particlesContainer = document.getElementById("particles");
// 事件监听
document.addEventListener("DOMContentLoaded", function () {
console.log("DOM fully loaded");
// 确保按钮存在
const numberButton = document.getElementById("numberButton");
if (numberButton) {
numberButton.addEventListener("click", function () {
// 创建数字语音学习界面
const voiceScreen = document.createElement("div");
voiceScreen.className = "start-menu";
voiceScreen.style.position = "absolute";
voiceScreen.innerHTML = `
<h1 class="start-title">数字语音</h1>
<div class="number-options" style="margin-top: 30px;">
<button class="number-btn" data-number="1">1</button>
<button class="number-btn" data-number="2">2</button>
<button class="number-btn" data-number="3">3</button>
<button class="number-btn" data-number="4">4</button>
<button class="number-btn" data-number="5">5</button>
</div>
<button class="start-button" style="margin-top: 30px;" id="backToMain">返回</button>
`;
document.querySelector(".main-container").appendChild(voiceScreen);
// 数字按钮点击事件
voiceScreen.querySelectorAll(".number-btn").forEach((btn) => {
btn.addEventListener("click", function () {
const number = parseInt(this.dataset.number);
speak2(`这是数字${number}`);
});
});
// 返回按钮事件
voiceScreen
.querySelector("#backToMain")
.addEventListener("click", function () {
voiceScreen.remove();
});
});
}
const audioGameButton = document.getElementById("audioGameButton");
if (audioGameButton) {
audioGameButton.addEventListener("click", () => initGame("audio"));
}
const pictureGameButton = document.getElementById("pictureGameButton");
if (pictureGameButton) {
pictureGameButton.addEventListener("click", () =>
initGame("picture")
);
}
const voiceButton = document.getElementById("voiceButton");
if (voiceButton) {
voiceButton.addEventListener("click", function () {
// 创建数字语音学习界面
const voiceScreen = document.createElement("div");
voiceScreen.className = "start-menu";
voiceScreen.style.position = "absolute";
voiceScreen.innerHTML = `
<h1 class="start-title">数字语音</h1>
<div class="number-options" style="margin-top: 30px;">
<button class="number-btn" data-number="1">1</button>
<button class="number-btn" data-number="2">2</button>
<button class="number-btn" data-number="3">3</button>
<button class="number-btn" data-number="4">4</button>
<button class="number-btn" data-number="5">5</button>
</div>
<button class="start-button" style="margin-top: 30px;" id="backToMain">返回</button>
`;
document.querySelector(".main-container").appendChild(voiceScreen);
// 数字按钮点击事件
voiceScreen.querySelectorAll(".number-btn").forEach((btn) => {
btn.addEventListener("click", function () {
const number = parseInt(this.dataset.number);
speak2(`这是数字${number}`);
});
});
// 返回按钮事件
voiceScreen
.querySelector("#backToMain")
.addEventListener("click", function () {
voiceScreen.remove();
});
});
}
if (backButton) {
backButton.addEventListener("click", backToMenu);
backButton.disabled = false;
}
if (victoryButton) {
victoryButton.addEventListener("click", backToMenu);
victoryButton.disabled = false;
}
// 数字按钮事件监听
document.querySelectorAll(".number-btn").forEach((btn) => {
btn.addEventListener("click", function () {
if (!this.disabled) {
checkAnswer(parseInt(this.dataset.number));
}
});
});
// 初始隐藏游戏和胜利界面
gameScreen.style.display = "none";
victoryScreen.style.display = "none";
// 显示开始菜单
startMenu.style.display = "flex";
startMenu.style.opacity = "1";
startMenu.style.pointerEvents = "auto";
});
// 音效控制
const soundToggle = document.getElementById("soundToggle");
let isSoundOn = true;
soundToggle.addEventListener("click", function () {
isSoundOn = !isSoundOn;
const soundIcon = this.querySelector(".sound-icon");
soundIcon.textContent = isSoundOn ? "🔊" : "🔇";
// 控制所有音频元素
document.querySelectorAll("audio").forEach((audio) => {
audio.muted = !isSoundOn;
});
// 播放音效状态提示
if (isSoundOn) {
speak2("音效已开启");
}
// 添加动画效果
this.style.transform = "scale(1.2)";
setTimeout(() => {
this.style.transform = "scale(1)";
}, 200);
});
// 初始化游戏
function initGame(mode = "picture") {
gameMode = mode;
currentQuestion = 0;
correctAnswers = 0;
gameStarted = true;
progressBar.style.width = "0%";
// 开始游戏跟踪
if (window.gameTracker) {
window.gameTracker.startGame(3, {
// 识数小精灵游戏ID
gameType: "number_recognition",
mode: mode,
totalQuestions: totalQuestions,
});
}
// 根据模式播放不同的背景音乐
const bgMusic = document.getElementById("bgMusic");
bgMusic.volume = 0.3;
bgMusic.muted = !isSoundOn;
if (mode === "picture") {
bgMusic.src = "MP3/背景音1.mp3";
speak2("小朋友,请观察图片并选择对应的数字");
} else if (mode === "audio") {
bgMusic.src = "MP3/背景音2.mp3";
speak2("小朋友,请听声音并选择对应的数字");
} else {
bgMusic.src = "MP3/背景音3.mp3";
}
bgMusic.play().catch((e) => console.log("自动播放被阻止:", e));
// 随机排序问题
shuffleArray(questions);
// 停止所有按钮的晃动效果
const numberButtons = document.querySelectorAll(".number-btn");
const audioButtons = document.querySelectorAll(".audio-btn");
const pictureButtons = document.querySelectorAll(".picture-btn");
numberButtons.forEach((btn) => {
btn.style.animation = "none";
});
audioButtons.forEach((btn) => {
btn.style.animation = "none";
});
pictureButtons.forEach((btn) => {
btn.style.animation = "none";
});
// 加载第一个问题
loadQuestion(currentQuestion);
// 显示游戏界面
startMenu.style.opacity = "0";
startMenu.style.pointerEvents = "none";
setTimeout(() => {
startMenu.style.display = "none";
gameScreen.style.display = "flex";
}, 500);
}
if (gameMode === "picture") {
speak2("小朋友,请观察图片并选择对应的数字");
} else {
speak2("小朋友,请听声音并选择对应的数字");
}
// 加载问题
function loadQuestion(index) {
if (index >= questions.length) {
shuffleArray(questions);
currentQuestion = 0;
}
// 重置错误计数器
window.errorCount = 0;
if (gameMode === "picture") {
gameImage.src = questions[index].image;
gameImage.style.display = "block";
} else {
gameImage.style.display = "none";
const correctNumber = questions[currentQuestion].answer;
speak2(`请找出数字${correctNumber}`);
}
feedback.style.opacity = "0";
feedback.textContent = "";
// 恢复所有数字按钮状态
const numberButtons = document.querySelectorAll(".number-btn");
numberButtons.forEach((btn) => {
btn.disabled = false;
btn.style.opacity = "1";
btn.style.cursor = "pointer";
btn.style.boxShadow = "0 10px 20px rgba(0, 0, 0, 0.2)";
});
// 清除之前的倒计时
if (timer) clearTimeout(timer);
// 设置5秒倒计时
timer = setTimeout(() => {
const correctNumber = questions[currentQuestion].answer;
const correctBtn = document.querySelector(
`.number-btn[data-number="${correctNumber}"]`
);
if (correctBtn) {
correctBtn.style.boxShadow = "0 0 20px 10px rgba(0, 255, 0, 0.5)";
correctBtn.style.transition = "box-shadow 2s ease-in-out";
// 添加晃动动画
correctBtn.style.animation = "bounce 0.5s infinite";
// 播放语音提示
if (gameMode === "picture") {
speak2("小朋友,选择正确的数字吧");
} else {
speak2(`请找出数字${correctNumber}`);
}
}
}, 5000);
}
// 检查答案
function checkAnswer(selectedNumber) {
if (!gameStarted) return;
// 清除倒计时
if (timer) clearTimeout(timer);
// 错误计数
if (typeof window.errorCount === "undefined") {
window.errorCount = 0;
}
const correctNumber = questions[currentQuestion].answer;
const isCorrect = selectedNumber === correctNumber;
// 详细数据打印
console.log("🎯 识数小精灵游戏 - 用户选择记录");
console.log("📊 问题信息:", {
问题编号: currentQuestion + 1,
问题内容: questions[currentQuestion].question || "未知问题",
正确答案: correctNumber,
用户选择: selectedNumber,
是否正确: isCorrect ? "✅ 正确" : "❌ 错误",
错误次数: window.errorCount,
});
console.log("📈 游戏进度:", {
当前得分: correctAnswers,
总问题数: totalQuestions,
完成进度: `${((correctAnswers / totalQuestions) * 100).toFixed(1)}%`,
});
console.log("⏰ 时间信息:", {
选择时间: new Date().toLocaleString("zh-CN"),
游戏时长: window.gameTracker
? window.gameTracker.getCurrentPlayTime() + "秒"
: "未知",
});
// 记录游戏尝试
if (window.gameTracker) {
window.gameTracker.recordAttempt();
}
if (isCorrect) {
// 正确答案处理
speak2("你太棒啦");
feedback.textContent = "✓";
feedback.className = "feedback correct";
feedback.style.opacity = "1";
// 移除正确按钮的晃动效果
const correctBtn = document.querySelector(
`.number-btn[data-number="${correctNumber}"]`
);
if (correctBtn) correctBtn.style.animation = "none";
// 禁用所有数字按钮
document.querySelectorAll(".number-btn").forEach((btn) => {
btn.disabled = true;
btn.style.opacity = "0.5";
btn.style.cursor = "not-allowed";
});
correctAnswers++;
progressBar.style.width = `${
(correctAnswers / totalQuestions) * 100
}%`;
createParticles(); // 正确答案时显示特效
// 记录正确答案
if (window.gameTracker) {
window.gameTracker.recordCorrect(10, {
question: questions[currentQuestion].question || "未知问题",
selected: selectedNumber,
correct: correctNumber,
questionNumber: currentQuestion + 1,
totalQuestions: totalQuestions,
errorCount: window.errorCount,
});
}
// 检查是否胜利
if (correctAnswers >= totalQuestions) {
showVictory();
} else {
// 延迟加载下一题
setTimeout(() => {
particlesContainer.innerHTML = ""; // 清除特效
currentQuestion++;
loadQuestion(currentQuestion);
}, 4000); // 延长到4秒
}
} else {
// 错误答案处理
speak2("答错了我们再想一想");
feedback.textContent = "✗";
feedback.className = "feedback incorrect";
feedback.style.opacity = "1";
// 增加错误计数
window.errorCount++;
// 记录错误答案
if (window.gameTracker) {
window.gameTracker.recordIncorrect(0, {
question: questions[currentQuestion].question || "未知问题",
selected: selectedNumber,
correct: correctNumber,
questionNumber: currentQuestion + 1,
totalQuestions: totalQuestions,
errorCount: window.errorCount,
});
}
// 禁用错误数字按钮
const numberButtons = document.querySelectorAll(".number-btn");
numberButtons.forEach((btn) => {
if (parseInt(btn.textContent) === selectedNumber) {
btn.disabled = true;
btn.style.opacity = "0.5";
btn.style.cursor = "not-allowed";
}
});
// 清除之前的计时器
if (timer) clearTimeout(timer);
// 如果错误达到2次立即显示提示
if (window.errorCount >= 2) {
const correctNumber = questions[currentQuestion].answer;
const correctBtn = document.querySelector(
`.number-btn[data-number="${correctNumber}"]`
);
if (correctBtn) {
correctBtn.style.boxShadow = "0 0 20px 10px rgba(0, 255, 0, 0.5)";
correctBtn.style.transition = "box-shadow 2s ease-in-out";
correctBtn.style.animation = "bounce 0.5s infinite";
speak2("小朋友,正确的数字是" + correctNumber);
}
} else {
// 设置5秒后显示正确答案提示
timer = setTimeout(() => {
const correctNumber = questions[currentQuestion].answer;
const correctBtn = document.querySelector(
`.number-btn[data-number="${correctNumber}"]`
);
if (correctBtn) {
correctBtn.style.boxShadow =
"0 0 20px 10px rgba(0, 255, 0, 0.5)";
correctBtn.style.transition = "box-shadow 2s ease-in-out";
correctBtn.style.animation = "bounce 0.5s infinite";
speak2("小朋友,正确的数字是" + correctNumber);
}
}, 5000);
}
}
}
// 显示胜利界面
function showVictory() {
speak2("小朋友你通关了你太厉害了");
gameScreen.style.display = "none";
victoryScreen.style.display = "flex";
// 根据游戏模式播放不同的胜利音效
const victorySound = document.createElement("audio");
if (isSoundOn) {
if (gameMode === "picture") {
victorySound.src = "MP3/最终胜利2.mp3";
} else {
victorySound.src = "MP3/胜利1.mp3";
}
// 受音量开关控制
const soundToggle = document.getElementById("soundToggle");
victorySound.muted = soundToggle.dataset.state === "off";
victorySound.play();
}
createParticles();
gameStarted = false;
}
// 返回菜单
function backToMenu() {
gameScreen.style.display = "none";
victoryScreen.style.display = "none";
startMenu.style.display = "flex";
startMenu.style.opacity = "1";
startMenu.style.pointerEvents = "auto";
// 清除粒子效果
particlesContainer.innerHTML = "";
// 暂停背景音乐
document.getElementById("bgMusic").pause();
// 重置游戏状态
gameStarted = false;
currentQuestion = 0;
correctAnswers = 0;
progressBar.style.width = "0%";
// 停止所有按钮的晃动效果
const numberButtons = document.querySelectorAll(".number-btn");
const audioButtons = document.querySelectorAll(".audio-btn");
const pictureButtons = document.querySelectorAll(".picture-btn");
numberButtons.forEach((btn) => {
btn.style.animation = "none";
});
audioButtons.forEach((btn) => {
btn.style.animation = "none";
});
pictureButtons.forEach((btn) => {
btn.style.animation = "none";
});
}
setTimeout(() => {
startMenu.style.opacity = "1";
startMenu.style.pointerEvents = "auto";
}, 100);
gameStarted = false;
// 重新开始游戏
function restartGame() {
victoryScreen.style.display = "none";
initGame();
}
// 数组随机排序
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
// 创建粒子特效
function createParticles() {
particlesContainer.innerHTML = "";
for (let i = 0; i < 50; i++) {
const particle = document.createElement("div");
particle.className = "particle";
// 随机位置
const x = Math.random() * 100;
const y = Math.random() * 100;
// 随机大小
const size = Math.random() * 10 + 5;
// 随机颜色
const hue = Math.random() * 60 + 30; // 黄色到橙色
particle.style.backgroundColor = `hsl(${hue}, 100%, 50%)`;
// 设置样式
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
particle.style.left = `${x}%`;
particle.style.top = `${y}%`;
// 动画
const duration = Math.random() * 3 + 2;
const delay = Math.random() * 2;
particle.style.animation = `float ${duration}s ease-in-out ${delay}s infinite`;
particlesContainer.appendChild(particle);
}
}
// 添加粒子动画关键帧
const style = document.createElement("style");
style.type = "text/css";
style.innerHTML = `
@keyframes float {
0% {
transform: translateY(0) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(-100vh) rotate(360deg);
opacity: 0;
}
}
`;
document.head.appendChild(style);
</script>
</body>
</html>
<style>
/* 悬浮提示样式 */
.tooltip {
position: absolute;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 10px 15px;
border-radius: 10px;
font-size: 1.2rem;
max-width: 200px;
text-align: center;
z-index: 100;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
</style>
<div class="tooltip" id="tooltip">
// ... existing code ...
<script>
// 悬浮提示功能
const tooltips = {
numberButton: "学习数字1-5的发音和写法",
audioGameButton: "听数字发音并选择正确答案",
pictureGameButton: "观察图片并选择对应的数字",
};
function showTooltip(buttonId, text) {
const button = document.getElementById(buttonId);
const tooltip = document.getElementById("tooltip");
const rect = button.getBoundingClientRect();
tooltip.textContent = text;
tooltip.style.left = `${
rect.left + rect.width / 2 - tooltip.offsetWidth / 2
}px`;
tooltip.style.top = `${rect.top - tooltip.offsetHeight - 10}px`;
tooltip.style.opacity = "1";
if (isSoundOn) {
speak2(text);
}
}
function hideTooltip() {
document.getElementById("tooltip").style.opacity = "0";
}
// 为菜单按钮添加悬浮事件
document.getElementById("numberButton").onmouseover = () =>
showTooltip("numberButton", tooltips.numberButton);
document.getElementById("numberButton").onmouseout = hideTooltip;
document.getElementById("audioGameButton").onmouseover = () =>
showTooltip("audioGameButton", tooltips.audioGameButton);
document.getElementById("audioGameButton").onmouseout = hideTooltip;
document.getElementById("pictureGameButton").onmouseover = () =>
showTooltip("pictureGameButton", tooltips.pictureGameButton);
document.getElementById("pictureGameButton").onmouseout = hideTooltip;
</script>
</div>