初始化

This commit is contained in:
zjh
2025-10-10 19:44:14 +08:00
parent 64db05717f
commit d5404c2a39
262 changed files with 44314 additions and 0 deletions

View File

@@ -0,0 +1,701 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI数学加减法游戏</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/virtualTeacher.js"></script>
<script src="../../js/gameVirtualTeacher.js"></script>
<style>
:root {
--primary: #ff9aa2;
--secondary: #ffb7b2;
--accent: #ffdac1;
--correct: #b5ead7;
--wrong: #ff9aa2;
--button: #70a1ff;
--text: #5e5346;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Comic Sans MS", "Marker Felt", "微软雅黑", sans-serif;
background-color: #f9f7f0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-image: radial-gradient(circle, #f5f5f5 10%, transparent 10%);
background-size: 30px 30px;
overflow: hidden;
}
.game-container {
width: 80%;
background-color: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
text-align: center;
position: relative;
overflow: hidden;
border: 5px solid #ffdac1;
}
h1 {
color: #ff6b6b;
margin-bottom: 30px;
font-size: 3rem;
text-shadow: 3px 3px 0 #ffdac1;
letter-spacing: 2px;
}
.question-area {
margin: 30px 0;
padding: 20px;
background-color: #f0f8ff;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.question {
font-size: 4rem;
margin: 20px 0;
color: #5e5346;
font-weight: bold;
}
.options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin: 30px 0;
}
.option-btn {
padding: 20px;
border-radius: 15px;
background-color: var(--button);
color: white;
border: none;
font-size: 2.5rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 5px 0 #4a6baf;
transition: all 0.2s ease;
min-height: 80px;
display: flex;
justify-content: center;
align-items: center;
}
.option-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.option-btn:active {
transform: translateY(5px);
box-shadow: 0 2px 0 #4a6baf;
}
.option-btn.correct {
background-color: var(--correct);
box-shadow: 0 5px 0 #8dd3c7;
}
.option-btn.wrong {
background-color: var(--wrong);
box-shadow: 0 5px 0 #e67e7e;
}
.score-area {
position: absolute;
top: 20px;
right: 20px;
background-color: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
font-size: 1.2rem;
font-weight: bold;
color: var(--text);
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #e0e0e0;
border-radius: 10px;
margin: 20px 0;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: var(--button);
transition: width 0.3s ease;
border-radius: 10px;
}
.message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
background-color: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
z-index: 100;
text-align: center;
max-width: 80%;
transition: all 0.3s ease;
border: 5px solid;
}
.message.show {
transform: translate(-50%, -50%) scale(1);
}
.message.correct {
border-color: #b5ead7;
background-color: #e8f8f3;
}
.message.wrong {
border-color: #ff9aa2;
background-color: #ffeef0;
}
.message h2 {
font-size: 3rem;
margin-bottom: 15px;
}
.message p {
font-size: 2rem;
margin-bottom: 20px;
}
.message-btn {
padding: 10px 20px;
border-radius: 50px;
border: none;
background-color: var(--button);
color: white;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s ease;
}
.message-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
z-index: 90;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
@media (max-width: 600px) {
.game-container {
width: 95%;
padding: 20px;
}
h1 {
font-size: 2rem;
}
.question {
font-size: 2.5rem;
}
.options {
grid-template-columns: 1fr;
}
.option-btn {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="score-area">
<div>得分: <span id="score">0</span></div>
<div>进度: <span id="progress">0</span>/<span id="total">3</span></div>
</div>
<h1>AI数学加减法游戏</h1>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="question-area">
<div class="question" id="questionText">准备开始...</div>
<div class="options" id="optionsContainer">
<!-- 选项将通过JavaScript动态生成 -->
</div>
</div>
</div>
<div class="message" id="message">
<h2 id="messageTitle">标题</h2>
<p id="messageText">内容</p>
<button class="message-btn" id="messageBtn">继续</button>
</div>
<script>
// DOM元素
const questionText = document.getElementById("questionText");
const optionsContainer = document.getElementById("optionsContainer");
const message = document.getElementById("message");
const messageTitle = document.getElementById("messageTitle");
const messageText = document.getElementById("messageText");
const messageBtn = document.getElementById("messageBtn");
const scoreElement = document.getElementById("score");
const progressElement = document.getElementById("progress");
const totalElement = document.getElementById("total");
const progressFill = document.getElementById("progressFill");
// 游戏状态
let currentQuestionIndex = 0;
let score = 0;
let correctCount = 0;
let gameStarted = false;
// 10以内加减法题目集合
const gameQuestions = [
{
question: "3 + 5 = ?",
options: ["6", "8", "9", "7"],
correct: 1, // 对应 "8"
explanation: "3 + 5 = 8"
},
{
question: "9 - 4 = ?",
options: ["4", "5", "6", "3"],
correct: 1, // 对应 "5"
explanation: "9 - 4 = 5"
},
{
question: "6 + 2 = ?",
options: ["7", "8", "9", "10"],
correct: 1, // 对应 "8"
explanation: "6 + 2 = 8"
}
];
// 随机打乱题目选项的函数
function shuffleOptions(question) {
const correctAnswer = question.options[question.correct];
const shuffledOptions = [...question.options];
// 使用Fisher-Yates算法打乱数组
for (let i = shuffledOptions.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledOptions[i], shuffledOptions[j]] = [shuffledOptions[j], shuffledOptions[i]];
}
// 找到正确答案的新位置
const newCorrectIndex = shuffledOptions.indexOf(correctAnswer);
return {
...question,
options: shuffledOptions,
correct: newCorrectIndex
};
}
// 生成更多随机题目的函数
function generateRandomQuestion() {
const isAddition = Math.random() > 0.5;
let num1, num2, answer, question;
if (isAddition) {
// 加法确保结果不超过10
num1 = Math.floor(Math.random() * 6) + 1; // 1-6
num2 = Math.floor(Math.random() * (10 - num1)) + 1; // 确保结果≤10
answer = num1 + num2;
question = `${num1} + ${num2} = ?`;
} else {
// 减法:确保结果不为负数
num1 = Math.floor(Math.random() * 9) + 2; // 2-10
num2 = Math.floor(Math.random() * num1) + 1; // 1到num1-1
answer = num1 - num2;
question = `${num1} - ${num2} = ?`;
}
// 生成错误选项
const wrongOptions = [];
while (wrongOptions.length < 3) {
let wrongAnswer;
if (isAddition) {
wrongAnswer = answer + (Math.random() > 0.5 ? 1 : -1) * (Math.floor(Math.random() * 3) + 1);
} else {
wrongAnswer = answer + (Math.random() > 0.5 ? 1 : -1) * (Math.floor(Math.random() * 3) + 1);
}
if (wrongAnswer >= 0 && wrongAnswer <= 20 && wrongAnswer !== answer && !wrongOptions.includes(wrongAnswer)) {
wrongOptions.push(wrongAnswer);
}
}
const options = [answer, ...wrongOptions].map(String);
return shuffleOptions({
question: question,
options: options,
correct: 0, // 初始正确答案在第一位
explanation: `${question.replace('?', answer)}`
});
}
// 初始化游戏题目
function initializeGame() {
// 使用预设题目和随机生成的题目
const allQuestions = [...gameQuestions];
// 为每个题目重新打乱选项
for (let i = 0; i < allQuestions.length; i++) {
allQuestions[i] = shuffleOptions(allQuestions[i]);
}
return allQuestions;
}
// 当前游戏题目
let currentGame = initializeGame();
// 显示当前题目
function showCurrentQuestion() {
if (currentQuestionIndex >= currentGame.length) {
endGame();
return;
}
const question = currentGame[currentQuestionIndex];
questionText.textContent = question.question;
// 清空选项容器
optionsContainer.innerHTML = "";
// 创建选项按钮
question.options.forEach((option, index) => {
const button = document.createElement("button");
button.className = "option-btn";
button.textContent = option;
button.onclick = () => selectAnswer(index, question);
optionsContainer.appendChild(button);
});
// 更新进度
progressElement.textContent = currentQuestionIndex + 1;
progressFill.style.width = `${((currentQuestionIndex + 1) / currentGame.length) * 100}%`;
// 虚拟老师朗读题目
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
setTimeout(() => {
const questionNumber = currentQuestionIndex + 1;
const readableQuestion = question.question.replace('=', '等于').replace('?', '多少');
window.gameVirtualTeacher.speak(`${questionNumber}题:${readableQuestion}`);
}, 800);
}
}
// 选择答案
function selectAnswer(selectedIndex, question) {
if (message.classList.contains("show")) return;
const isCorrect = selectedIndex === question.correct;
const selectedButton = optionsContainer.children[selectedIndex];
const correctButton = optionsContainer.children[question.correct];
// 禁用所有按钮
Array.from(optionsContainer.children).forEach(btn => {
btn.style.pointerEvents = 'none';
});
// 显示答案效果
selectedButton.classList.add(isCorrect ? "correct" : "wrong");
if (!isCorrect) {
correctButton.classList.add("correct");
}
// 虚拟老师反馈
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
setTimeout(() => {
if (isCorrect) {
const encouragements = [
"太棒了!答对了!",
"很好!你答对了!",
"正确!做得很棒!",
"厉害!继续保持!"
];
const randomEncouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
window.gameVirtualTeacher.speak(randomEncouragement);
window.gameVirtualTeacher.recordCorrect();
} else {
const hints = [
"没关系,再想想看!",
"不要紧,下次会更好!",
"正确答案是" + question.options[question.correct],
"让我们继续努力!"
];
const randomHint = hints[Math.floor(Math.random() * hints.length)];
window.gameVirtualTeacher.speak(randomHint);
window.gameVirtualTeacher.recordIncorrect();
}
}, 300);
}
// 更新分数
if (isCorrect) {
correctCount++;
score += 10;
scoreElement.textContent = score;
}
// 显示结果消息
const messageText = isCorrect
? `太棒了!${question.explanation}`
: `再想想!正确答案是 ${question.explanation}`;
setTimeout(() => {
showMessage(isCorrect, messageText);
if (isCorrect) {
createConfetti();
}
}, 500);
}
// 显示消息
function showMessage(isCorrect, text) {
message.className = "message " + (isCorrect ? "correct" : "wrong");
messageTitle.textContent = isCorrect ? "太棒了!" : "再试一次";
messageText.textContent = text;
message.classList.add("show");
}
// 创建彩色纸屑效果
function createConfetti() {
const colors = [
"#FF9AA2",
"#FFB7B2",
"#FFDAC1",
"#E2F0CB",
"#B5EAD7",
"#C7CEEA",
];
for (let i = 0; i < 50; i++) {
const confetti = document.createElement("div");
confetti.className = "confetti";
confetti.style.left = `${Math.random() * 100}%`;
confetti.style.backgroundColor =
colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = `${Math.random() * 10 + 5}px`;
confetti.style.height = `${Math.random() * 10 + 5}px`;
confetti.style.animation = `confetti-fall ${
Math.random() * 2 + 2
}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
document.body.appendChild(confetti);
setTimeout(() => {
confetti.remove();
}, 3000);
}
}
// 下一题
function nextQuestion() {
message.classList.remove("show");
// 重新启用按钮
Array.from(optionsContainer.children).forEach(btn => {
btn.style.pointerEvents = 'auto';
btn.classList.remove('correct', 'wrong');
});
currentQuestionIndex++;
showCurrentQuestion();
}
// 结束游戏
function endGame() {
const successRate = (correctCount / currentGame.length) * 100;
message.className = "message correct";
messageTitle.textContent = "游戏完成!";
messageText.textContent = `恭喜你完成了游戏!\n得分: ${score}\n正确率: ${successRate.toFixed(1)}%\n\n${getEncouragementMessage(successRate)}`;
message.classList.add("show");
// 虚拟老师游戏结束语音
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
setTimeout(() => {
let endMessage = `游戏完成!你的得分是${score}分,正确率${successRate.toFixed(1)}%。`;
if (successRate === 100) {
endMessage += "太棒了!你全部答对了,你是数学小天才!";
} else if (successRate >= 66) {
endMessage += "做得很好!继续加油,你会越来越棒的!";
} else {
endMessage += "不错的开始!多多练习,下次一定会更好!";
}
window.gameVirtualTeacher.speak(endMessage);
window.gameVirtualTeacher.gameEnd();
}, 1000);
}
messageBtn.textContent = "重新开始";
messageBtn.onclick = restartGame;
// 创建庆祝动画
createConfetti();
}
// 根据成绩给出鼓励语
function getEncouragementMessage(successRate) {
if (successRate === 100) {
return "完美!你是数学小天才!🌟";
} else if (successRate >= 66) {
return "做得很好!继续加油!👏";
} else {
return "不错的开始!多练习会更棒!💪";
}
}
// 重新开始游戏
function restartGame() {
currentQuestionIndex = 0;
score = 0;
correctCount = 0;
scoreElement.textContent = "0";
progressElement.textContent = "0";
progressFill.style.width = "0%";
// 重新初始化游戏题目(重新打乱选项)
currentGame = initializeGame();
message.classList.remove("show");
messageBtn.textContent = "继续";
messageBtn.onclick = nextQuestion;
// 虚拟老师重新开始游戏
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
window.gameVirtualTeacher.gameStart("AI数学加减法游戏");
setTimeout(() => {
window.gameVirtualTeacher.speak("好的!让我们重新开始挑战吧!");
}, 500);
}
showCurrentQuestion();
}
// 事件监听
messageBtn.addEventListener("click", nextQuestion);
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", function () {
console.log("🎮 数学加减法游戏初始化完成");
// 初始化虚拟老师
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher
.init({
intro: "欢迎来到AI数学加减法游戏我会帮你学习10以内的加减法运算还会为你朗读每道题目。准备好了吗",
})
.then(() => {
console.log("🦉 AI数学加减法游戏虚拟老师初始化成功");
})
.catch((error) => {
console.error("❌ 虚拟老师初始化失败:", error);
});
}
// 初始化后端集成(如果存在)
const initBackend = async () => {
try {
if (window.userManager && window.dataManager) {
await Promise.all([window.userManager.init(), window.dataManager.init()]);
console.log("后端集成初始化完成");
}
} catch (error) {
console.warn("后端集成初始化失败,但游戏仍可正常运行:", error);
}
};
initBackend();
// 显示开始消息
setTimeout(() => {
message.className = "message correct";
messageTitle.textContent = "欢迎!";
messageText.textContent = "我会为你朗读每道题目!\n让我们开始吧";
message.classList.add("show");
// 虚拟老师欢迎语音
if (window.gameVirtualTeacher) {
setTimeout(() => {
window.gameVirtualTeacher.speak("欢迎来到数学加减法游戏我会帮你学习10以内的加减法还会为你朗读每道题目。准备好开始了吗");
}, 100);
}
messageBtn.textContent = "开始游戏";
messageBtn.onclick = () => {
message.classList.remove("show");
messageBtn.textContent = "继续";
messageBtn.onclick = nextQuestion;
gameStarted = true;
// 虚拟老师游戏开始
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameStart("AI数学加减法游戏");
}
showCurrentQuestion();
};
}, 500);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,653 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI数学比大小游戏</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/virtualTeacher.js"></script>
<script src="../../js/gameVirtualTeacher.js"></script>
<script src="../../js/aiGameGenerator.js"></script>
<style>
:root {
--primary: #ff9aa2;
--secondary: #ffb7b2;
--accent: #ffdac1;
--correct: #b5ead7;
--wrong: #ff9aa2;
--button: #70a1ff;
--text: #5e5346;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Comic Sans MS", "Marker Felt", "微软雅黑", sans-serif;
background-color: #f9f7f0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-image: radial-gradient(circle, #f5f5f5 10%, transparent 10%);
background-size: 30px 30px;
overflow: hidden;
}
.game-container {
width: 80%;
background-color: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
text-align: center;
position: relative;
overflow: hidden;
border: 5px solid #ffdac1;
}
h1 {
color: #ff6b6b;
margin-bottom: 30px;
font-size: 3rem;
text-shadow: 3px 3px 0 #ffdac1;
letter-spacing: 2px;
}
.game-area {
display: flex;
justify-content: space-around;
margin: 30px 0;
}
.math-card {
width: 45%;
padding: 20px;
background-color: #f0f8ff;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
position: relative;
transition: all 0.3s ease;
}
.math-card:hover,
.math-card.active {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
.math-card::before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
border: 3px dashed #ffb7b2;
border-radius: 20px;
z-index: -1;
opacity: 0.5;
}
.equation {
font-size: 5rem;
margin: 20px 0;
color: #5e5346;
font-weight: bold;
}
.select-btn {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: var(--button);
color: white;
border: none;
font-size: 2rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 5px 0 #4a6baf;
transition: all 0.2s ease;
margin-top: 10px;
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
}
.select-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.select-btn:active {
transform: translateY(5px);
box-shadow: 0 2px 0 #4a6baf;
}
.score-area {
position: absolute;
top: 20px;
right: 20px;
background-color: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
font-size: 1.2rem;
font-weight: bold;
color: var(--text);
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #e0e0e0;
border-radius: 10px;
margin: 20px 0;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: var(--button);
transition: width 0.3s ease;
border-radius: 10px;
}
.message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
background-color: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
z-index: 100;
text-align: center;
max-width: 80%;
transition: all 0.3s ease;
border: 5px solid;
}
.message.show {
transform: translate(-50%, -50%) scale(1);
}
.message.correct {
border-color: #b5ead7;
background-color: #e8f8f3;
}
.message.wrong {
border-color: #ff9aa2;
background-color: #ffeef0;
}
.message h2 {
font-size: 3rem;
margin-bottom: 15px;
}
.message p {
font-size: 2rem;
margin-bottom: 20px;
}
.message-btn {
padding: 10px 20px;
border-radius: 50px;
border: none;
background-color: var(--button);
color: white;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s ease;
}
.message-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
z-index: 90;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
@media (max-width: 600px) {
.game-area {
flex-direction: column;
align-items: center;
}
.math-card {
width: 90%;
margin-bottom: 20px;
}
h1 {
font-size: 2rem;
}
.equation {
font-size: 3rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="score-area">
<div>得分: <span id="score">0</span></div>
<div>进度: <span id="progress">0</span>/<span id="total">5</span></div>
</div>
<h1>AI数学比大小游戏</h1>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="game-area">
<div class="math-card" id="leftCard">
<div class="equation" id="leftEquation">准备中...</div>
<button class="select-btn" id="leftBtn">选择</button>
</div>
<div class="math-card" id="rightCard">
<div class="equation" id="rightEquation">准备中...</div>
<button class="select-btn" id="rightBtn">选择</button>
</div>
</div>
</div>
<div class="message" id="message">
<h2 id="messageTitle">标题</h2>
<p id="messageText">内容</p>
<button class="message-btn" id="messageBtn">继续</button>
</div>
<script>
// DOM元素
const leftEquation = document.getElementById("leftEquation");
const rightEquation = document.getElementById("rightEquation");
const leftBtn = document.getElementById("leftBtn");
const rightBtn = document.getElementById("rightBtn");
const message = document.getElementById("message");
const messageTitle = document.getElementById("messageTitle");
const messageText = document.getElementById("messageText");
const messageBtn = document.getElementById("messageBtn");
const scoreElement = document.getElementById("score");
const progressElement = document.getElementById("progress");
const totalElement = document.getElementById("total");
const progressFill = document.getElementById("progressFill");
// 游戏状态
let currentGame = null;
let currentQuestionIndex = 0;
let leftValue = 0;
let rightValue = 0;
let correctAnswer = "";
let score = 0;
let correctCount = 0;
let gameStarted = false;
let gameId = "ai_math_comparison_" + Date.now();
// 初始化AI游戏生成器
async function initAIGame() {
try {
if (!window.aiGameGenerator) {
throw new Error("AI游戏生成器未加载");
}
await window.aiGameGenerator.init();
console.log("✅ AI游戏生成器初始化成功");
// 生成数学比大小游戏
currentGame = window.aiGameGenerator.generatePersonalizedGame(
"math",
"quiz",
5
);
if (currentGame && currentGame.questions.length > 0) {
// 筛选比大小题目
const comparisonQuestions = currentGame.questions.filter(
(q) =>
q.question.includes("__") ||
q.question.includes(">") ||
q.question.includes("<") ||
q.question.includes("=")
);
if (comparisonQuestions.length > 0) {
currentGame.questions = comparisonQuestions.slice(0, 5);
}
totalElement.textContent = currentGame.questions.length;
console.log("🎮 AI数学比大小游戏生成成功:", currentGame);
return true;
} else {
throw new Error("无法生成游戏题目");
}
} catch (error) {
console.error("❌ AI游戏初始化失败:", error);
return false;
}
}
// 显示当前题目
function showCurrentQuestion() {
if (
!currentGame ||
currentQuestionIndex >= currentGame.questions.length
) {
endGame();
return;
}
const question = currentGame.questions[currentQuestionIndex];
// 解析比大小题目
if (question.question.includes("__")) {
// 格式如 "5 __ 3"
const parts = question.question.split("__");
if (parts.length === 2) {
leftValue = parseInt(parts[0].trim());
rightValue = parseInt(parts[1].trim());
leftEquation.textContent = leftValue.toString();
rightEquation.textContent = rightValue.toString();
}
} else {
// 生成随机数字进行比较
leftValue = Math.floor(Math.random() * 10) + 1;
rightValue = Math.floor(Math.random() * 10) + 1;
leftEquation.textContent = leftValue.toString();
rightEquation.textContent = rightValue.toString();
}
// 确定正确答案
if (leftValue > rightValue) {
correctAnswer = "left";
} else if (rightValue > leftValue) {
correctAnswer = "right";
} else {
correctAnswer = "equal";
}
// 更新进度
progressElement.textContent = currentQuestionIndex + 1;
progressFill.style.width = `${
((currentQuestionIndex + 1) / currentGame.questions.length) * 100
}%`;
// 清除卡片样式
document.querySelectorAll(".math-card")[0].className = "math-card";
document.querySelectorAll(".math-card")[1].className = "math-card";
}
// 检查答案
function checkAnswer(selectedSide) {
if (message.classList.contains("show")) return;
let isCorrect = false;
let messageText = "";
// 高亮选中的卡片
document.querySelectorAll(".math-card")[
selectedSide === "left" ? 0 : 1
].className = "math-card active";
if (correctAnswer === "equal") {
isCorrect = true;
messageText = "两边一样大!";
} else if (selectedSide === correctAnswer) {
isCorrect = true;
messageText = `对了!${leftValue} ${
selectedSide === "left" ? ">" : "<"
} ${rightValue}`;
} else {
isCorrect = false;
messageText = `不对哦!${leftValue} ${
correctAnswer === "left" ? ">" : "<"
} ${rightValue}`;
}
// 虚拟老师反馈
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
setTimeout(() => {
if (isCorrect) {
window.gameVirtualTeacher.recordCorrect();
} else {
window.gameVirtualTeacher.recordIncorrect();
}
}, 300);
}
// 更新分数
if (isCorrect) {
correctCount++;
score += 10;
scoreElement.textContent = score;
}
// 记录游戏数据
if (gameStarted && window.gameTracker) {
if (isCorrect) {
window.gameTracker.recordCorrect(10, {
question: `${leftValue} vs ${rightValue}`,
selected: selectedSide,
correct: correctAnswer,
leftValue: leftValue,
rightValue: rightValue,
questionNumber: currentQuestionIndex + 1,
});
} else {
window.gameTracker.recordIncorrect(0, {
question: `${leftValue} vs ${rightValue}`,
selected: selectedSide,
correct: correctAnswer,
leftValue: leftValue,
rightValue: rightValue,
questionNumber: currentQuestionIndex + 1,
});
}
}
showMessage(isCorrect, messageText);
if (isCorrect) {
createConfetti();
}
}
// 显示消息
function showMessage(isCorrect, text) {
message.className = "message " + (isCorrect ? "correct" : "wrong");
messageTitle.textContent = isCorrect ? "太棒了!" : "再试一次";
messageText.textContent = text;
message.classList.add("show");
}
// 创建彩色纸屑效果
function createConfetti() {
const colors = [
"#FF9AA2",
"#FFB7B2",
"#FFDAC1",
"#E2F0CB",
"#B5EAD7",
"#C7CEEA",
];
for (let i = 0; i < 50; i++) {
const confetti = document.createElement("div");
confetti.className = "confetti";
confetti.style.left = `${Math.random() * 100}%`;
confetti.style.backgroundColor =
colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = `${Math.random() * 10 + 5}px`;
confetti.style.height = `${Math.random() * 10 + 5}px`;
confetti.style.animation = `confetti-fall ${
Math.random() * 2 + 2
}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
document.body.appendChild(confetti);
setTimeout(() => {
confetti.remove();
}, 3000);
}
}
// 下一题
function nextQuestion() {
message.classList.remove("show");
currentQuestionIndex++;
showCurrentQuestion();
}
// 结束游戏
function endGame() {
const successRate = (correctCount / currentGame.questions.length) * 100;
message.className = "message correct";
messageTitle.textContent = "游戏完成!";
messageText.textContent = `恭喜你完成了游戏!\n得分: ${score}\n正确率: ${successRate.toFixed(
1
)}%`;
message.classList.add("show");
// 虚拟老师游戏结束
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameEnd();
}
// 记录游戏结果
if (gameStarted && window.gameTracker) {
if (successRate >= 80) {
window.gameTracker.recordWin(score, {
totalQuestions: currentGame.questions.length,
correctCount: correctCount,
successRate: successRate,
});
} else {
window.gameTracker.recordLose(score, {
totalQuestions: currentGame.questions.length,
correctCount: correctCount,
successRate: successRate,
});
}
}
messageBtn.textContent = "重新开始";
messageBtn.onclick = restartGame;
}
// 重新开始游戏
function restartGame() {
currentQuestionIndex = 0;
score = 0;
correctCount = 0;
scoreElement.textContent = "0";
progressElement.textContent = "0";
progressFill.style.width = "0%";
message.classList.remove("show");
messageBtn.textContent = "继续";
messageBtn.onclick = nextQuestion;
showCurrentQuestion();
}
// 事件监听
leftBtn.addEventListener("click", () => checkAnswer("left"));
rightBtn.addEventListener("click", () => checkAnswer("right"));
messageBtn.addEventListener("click", nextQuestion);
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", async function () {
// 初始化虚拟老师
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher
.init({
intro:
"欢迎来到AI数学比大小游戏我会帮你学习数字比较准备好了吗",
})
.then(() => {
console.log("🦉 AI数学比大小游戏虚拟老师初始化成功");
})
.catch((error) => {
console.error("❌ 虚拟老师初始化失败:", error);
});
}
// 初始化后端集成
Promise.all([window.userManager.init(), window.dataManager.init()])
.then(async () => {
console.log("后端集成初始化完成");
// 初始化AI游戏
const success = await initAIGame();
if (success) {
// 开始游戏跟踪
if (window.gameTracker) {
window.gameTracker.startGame(gameId, {
gameType: "ai_math_comparison",
difficulty: "adaptive",
});
}
// 虚拟老师游戏开始
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameStart("AI数学比大小游戏");
setTimeout(() => {
window.gameVirtualTeacher.speak(
"欢迎来到AI数学比大小游戏我会帮你学习数字比较准备好了吗"
);
}, 1000);
}
gameStarted = true;
showCurrentQuestion();
} else {
showMessage(false, "游戏初始化失败,请刷新页面重试");
}
})
.catch((error) => {
console.error("后端集成初始化失败:", error);
showMessage(false, "系统初始化失败,请刷新页面重试");
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,609 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI生活安全游戏</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/virtualTeacher.js"></script>
<script src="../../js/gameVirtualTeacher.js"></script>
<script src="../../js/aiGameGenerator.js"></script>
<style>
:root {
--primary: #ff9aa2;
--secondary: #ffb7b2;
--accent: #ffdac1;
--correct: #b5ead7;
--wrong: #ff9aa2;
--button: #70a1ff;
--text: #5e5346;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Comic Sans MS", "Marker Felt", "微软雅黑", sans-serif;
background-color: #f9f7f0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-image: radial-gradient(circle, #f5f5f5 10%, transparent 10%);
background-size: 30px 30px;
overflow: hidden;
}
.game-container {
width: 80%;
background-color: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
text-align: center;
position: relative;
overflow: hidden;
border: 5px solid #ffdac1;
}
h1 {
color: #ff6b6b;
margin-bottom: 30px;
font-size: 3rem;
text-shadow: 3px 3px 0 #ffdac1;
letter-spacing: 2px;
}
.question-area {
margin: 30px 0;
padding: 20px;
background-color: #f0f8ff;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.question {
font-size: 2.5rem;
margin: 20px 0;
color: #5e5346;
font-weight: bold;
line-height: 1.4;
}
.options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin: 30px 0;
}
.option-btn {
padding: 20px;
border-radius: 15px;
background-color: var(--button);
color: white;
border: none;
font-size: 1.8rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 5px 0 #4a6baf;
transition: all 0.2s ease;
min-height: 80px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.option-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.option-btn:active {
transform: translateY(5px);
box-shadow: 0 2px 0 #4a6baf;
}
.option-btn.correct {
background-color: var(--correct);
box-shadow: 0 5px 0 #8dd3c7;
}
.option-btn.wrong {
background-color: var(--wrong);
box-shadow: 0 5px 0 #e67e7e;
}
.score-area {
position: absolute;
top: 20px;
right: 20px;
background-color: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
font-size: 1.2rem;
font-weight: bold;
color: var(--text);
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #e0e0e0;
border-radius: 10px;
margin: 20px 0;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: var(--button);
transition: width 0.3s ease;
border-radius: 10px;
}
.message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
background-color: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
z-index: 100;
text-align: center;
max-width: 80%;
transition: all 0.3s ease;
border: 5px solid;
}
.message.show {
transform: translate(-50%, -50%) scale(1);
}
.message.correct {
border-color: #b5ead7;
background-color: #e8f8f3;
}
.message.wrong {
border-color: #ff9aa2;
background-color: #ffeef0;
}
.message h2 {
font-size: 3rem;
margin-bottom: 15px;
}
.message p {
font-size: 1.8rem;
margin-bottom: 20px;
line-height: 1.4;
}
.message-btn {
padding: 10px 20px;
border-radius: 50px;
border: none;
background-color: var(--button);
color: white;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s ease;
}
.message-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
z-index: 90;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
@media (max-width: 600px) {
.game-container {
width: 95%;
padding: 20px;
}
h1 {
font-size: 2rem;
}
.question {
font-size: 1.8rem;
}
.options {
grid-template-columns: 1fr;
}
.option-btn {
font-size: 1.5rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="score-area">
<div>得分: <span id="score">0</span></div>
<div>进度: <span id="progress">0</span>/<span id="total">5</span></div>
</div>
<h1>AI生活安全游戏</h1>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="question-area">
<div class="question" id="questionText">准备开始...</div>
<div class="options" id="optionsContainer">
<!-- 选项将通过JavaScript动态生成 -->
</div>
</div>
</div>
<div class="message" id="message">
<h2 id="messageTitle">标题</h2>
<p id="messageText">内容</p>
<button class="message-btn" id="messageBtn">继续</button>
</div>
<script>
// DOM元素
const questionText = document.getElementById("questionText");
const optionsContainer = document.getElementById("optionsContainer");
const message = document.getElementById("message");
const messageTitle = document.getElementById("messageTitle");
const messageText = document.getElementById("messageText");
const messageBtn = document.getElementById("messageBtn");
const scoreElement = document.getElementById("score");
const progressElement = document.getElementById("progress");
const totalElement = document.getElementById("total");
const progressFill = document.getElementById("progressFill");
// 游戏状态
let currentGame = null;
let currentQuestionIndex = 0;
let score = 0;
let correctCount = 0;
let gameStarted = false;
let gameId = "ai_life_safety_" + Date.now();
// 初始化AI游戏生成器
async function initAIGame() {
try {
if (!window.aiGameGenerator) {
throw new Error("AI游戏生成器未加载");
}
await window.aiGameGenerator.init();
console.log("✅ AI游戏生成器初始化成功");
// 生成生活安全游戏
currentGame = window.aiGameGenerator.generatePersonalizedGame(
"life",
"quiz",
5
);
if (currentGame && currentGame.questions.length > 0) {
// 筛选安全题目
const safetyQuestions = currentGame.questions.filter(
(q) =>
q.question.includes("安全") ||
q.question.includes("应该") ||
q.question.includes("过马路") ||
q.question.includes("陌生人") ||
q.question.includes("火灾") ||
q.question.includes("地震")
);
if (safetyQuestions.length > 0) {
currentGame.questions = safetyQuestions.slice(0, 5);
}
totalElement.textContent = currentGame.questions.length;
console.log("🎮 AI生活安全游戏生成成功:", currentGame);
return true;
} else {
throw new Error("无法生成游戏题目");
}
} catch (error) {
console.error("❌ AI游戏初始化失败:", error);
return false;
}
}
// 显示当前题目
function showCurrentQuestion() {
if (
!currentGame ||
currentQuestionIndex >= currentGame.questions.length
) {
endGame();
return;
}
const question = currentGame.questions[currentQuestionIndex];
questionText.textContent = question.question;
// 清空选项容器
optionsContainer.innerHTML = "";
// 创建选项按钮
question.options.forEach((option, index) => {
const button = document.createElement("button");
button.className = "option-btn";
button.textContent = option;
button.onclick = () => selectAnswer(index, question);
optionsContainer.appendChild(button);
});
// 更新进度
progressElement.textContent = currentQuestionIndex + 1;
progressFill.style.width = `${
((currentQuestionIndex + 1) / currentGame.questions.length) * 100
}%`;
}
// 选择答案
function selectAnswer(selectedIndex, question) {
if (message.classList.contains("show")) return;
const isCorrect = selectedIndex === question.correct;
const selectedButton = optionsContainer.children[selectedIndex];
const correctButton = optionsContainer.children[question.correct];
// 显示答案效果
selectedButton.classList.add(isCorrect ? "correct" : "wrong");
if (!isCorrect) {
correctButton.classList.add("correct");
}
// 虚拟老师反馈
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
setTimeout(() => {
if (isCorrect) {
window.gameVirtualTeacher.recordCorrect();
} else {
window.gameVirtualTeacher.recordIncorrect();
}
}, 300);
}
// 更新分数
if (isCorrect) {
correctCount++;
score += 10;
scoreElement.textContent = score;
}
// 记录游戏数据
if (gameStarted && window.gameTracker) {
if (isCorrect) {
window.gameTracker.recordCorrect(10, {
question: question.question,
selected: question.options[selectedIndex],
correct: question.options[question.correct],
questionNumber: currentQuestionIndex + 1,
});
} else {
window.gameTracker.recordIncorrect(0, {
question: question.question,
selected: question.options[selectedIndex],
correct: question.options[question.correct],
questionNumber: currentQuestionIndex + 1,
});
}
}
// 显示结果消息
const messageText = isCorrect
? `太棒了!${question.question} 的正确答案是 ${
question.options[question.correct]
}`
: `再想想!正确答案是 ${question.options[question.correct]}`;
showMessage(isCorrect, messageText);
if (isCorrect) {
createConfetti();
}
}
// 显示消息
function showMessage(isCorrect, text) {
message.className = "message " + (isCorrect ? "correct" : "wrong");
messageTitle.textContent = isCorrect ? "太棒了!" : "再试一次";
messageText.textContent = text;
message.classList.add("show");
}
// 创建彩色纸屑效果
function createConfetti() {
const colors = [
"#FF9AA2",
"#FFB7B2",
"#FFDAC1",
"#E2F0CB",
"#B5EAD7",
"#C7CEEA",
];
for (let i = 0; i < 50; i++) {
const confetti = document.createElement("div");
confetti.className = "confetti";
confetti.style.left = `${Math.random() * 100}%`;
confetti.style.backgroundColor =
colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = `${Math.random() * 10 + 5}px`;
confetti.style.height = `${Math.random() * 10 + 5}px`;
confetti.style.animation = `confetti-fall ${
Math.random() * 2 + 2
}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
document.body.appendChild(confetti);
setTimeout(() => {
confetti.remove();
}, 3000);
}
}
// 下一题
function nextQuestion() {
message.classList.remove("show");
currentQuestionIndex++;
showCurrentQuestion();
}
// 结束游戏
function endGame() {
const successRate = (correctCount / currentGame.questions.length) * 100;
message.className = "message correct";
messageTitle.textContent = "游戏完成!";
messageText.textContent = `恭喜你完成了游戏!\n得分: ${score}\n正确率: ${successRate.toFixed(
1
)}%`;
message.classList.add("show");
// 虚拟老师游戏结束
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameEnd();
}
// 记录游戏结果
if (gameStarted && window.gameTracker) {
if (successRate >= 80) {
window.gameTracker.recordWin(score, {
totalQuestions: currentGame.questions.length,
correctCount: correctCount,
successRate: successRate,
});
} else {
window.gameTracker.recordLose(score, {
totalQuestions: currentGame.questions.length,
correctCount: correctCount,
successRate: successRate,
});
}
}
messageBtn.textContent = "重新开始";
messageBtn.onclick = restartGame;
}
// 重新开始游戏
function restartGame() {
currentQuestionIndex = 0;
score = 0;
correctCount = 0;
scoreElement.textContent = "0";
progressElement.textContent = "0";
progressFill.style.width = "0%";
message.classList.remove("show");
messageBtn.textContent = "继续";
messageBtn.onclick = nextQuestion;
showCurrentQuestion();
}
// 事件监听
messageBtn.addEventListener("click", nextQuestion);
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", async function () {
// 初始化虚拟老师
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher
.init({
intro:
"欢迎来到AI生活安全游戏我会帮你学习生活中的安全知识准备好了吗",
})
.then(() => {
console.log("🦉 AI生活安全游戏虚拟老师初始化成功");
})
.catch((error) => {
console.error("❌ 虚拟老师初始化失败:", error);
});
}
// 初始化后端集成
Promise.all([window.userManager.init(), window.dataManager.init()])
.then(async () => {
console.log("后端集成初始化完成");
// 初始化AI游戏
const success = await initAIGame();
if (success) {
// 开始游戏跟踪
if (window.gameTracker) {
window.gameTracker.startGame(gameId, {
gameType: "ai_life_safety",
difficulty: "adaptive",
});
}
// 虚拟老师游戏开始
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameStart("AI生活安全游戏");
setTimeout(() => {
window.gameVirtualTeacher.speak(
"欢迎来到AI生活安全游戏我会帮你学习生活中的安全知识准备好了吗"
);
}, 1000);
}
gameStarted = true;
showCurrentQuestion();
} else {
showMessage(false, "游戏初始化失败,请刷新页面重试");
}
})
.catch((error) => {
console.error("后端集成初始化失败:", error);
showMessage(false, "系统初始化失败,请刷新页面重试");
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,600 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI语文拼音游戏</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/virtualTeacher.js"></script>
<script src="../../js/gameVirtualTeacher.js"></script>
<script src="../../js/aiGameGenerator.js"></script>
<style>
:root {
--primary: #ff9aa2;
--secondary: #ffb7b2;
--accent: #ffdac1;
--correct: #b5ead7;
--wrong: #ff9aa2;
--button: #70a1ff;
--text: #5e5346;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Comic Sans MS", "Marker Felt", "微软雅黑", sans-serif;
background-color: #f9f7f0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-image: radial-gradient(circle, #f5f5f5 10%, transparent 10%);
background-size: 30px 30px;
overflow: hidden;
}
.game-container {
width: 80%;
background-color: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
text-align: center;
position: relative;
overflow: hidden;
border: 5px solid #ffdac1;
}
h1 {
color: #ff6b6b;
margin-bottom: 30px;
font-size: 3rem;
text-shadow: 3px 3px 0 #ffdac1;
letter-spacing: 2px;
}
.question-area {
margin: 30px 0;
padding: 20px;
background-color: #f0f8ff;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.question {
font-size: 4rem;
margin: 20px 0;
color: #5e5346;
font-weight: bold;
}
.options {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin: 30px 0;
}
.option-btn {
padding: 20px;
border-radius: 15px;
background-color: var(--button);
color: white;
border: none;
font-size: 2.5rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 5px 0 #4a6baf;
transition: all 0.2s ease;
min-height: 80px;
display: flex;
justify-content: center;
align-items: center;
}
.option-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.option-btn:active {
transform: translateY(5px);
box-shadow: 0 2px 0 #4a6baf;
}
.option-btn.correct {
background-color: var(--correct);
box-shadow: 0 5px 0 #8dd3c7;
}
.option-btn.wrong {
background-color: var(--wrong);
box-shadow: 0 5px 0 #e67e7e;
}
.score-area {
position: absolute;
top: 20px;
right: 20px;
background-color: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
font-size: 1.2rem;
font-weight: bold;
color: var(--text);
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #e0e0e0;
border-radius: 10px;
margin: 20px 0;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: var(--button);
transition: width 0.3s ease;
border-radius: 10px;
}
.message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
background-color: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
z-index: 100;
text-align: center;
max-width: 80%;
transition: all 0.3s ease;
border: 5px solid;
}
.message.show {
transform: translate(-50%, -50%) scale(1);
}
.message.correct {
border-color: #b5ead7;
background-color: #e8f8f3;
}
.message.wrong {
border-color: #ff9aa2;
background-color: #ffeef0;
}
.message h2 {
font-size: 3rem;
margin-bottom: 15px;
}
.message p {
font-size: 2rem;
margin-bottom: 20px;
}
.message-btn {
padding: 10px 20px;
border-radius: 50px;
border: none;
background-color: var(--button);
color: white;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s ease;
}
.message-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
z-index: 90;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
@media (max-width: 600px) {
.game-container {
width: 95%;
padding: 20px;
}
h1 {
font-size: 2rem;
}
.question {
font-size: 2.5rem;
}
.options {
grid-template-columns: 1fr;
}
.option-btn {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<div class="score-area">
<div>得分: <span id="score">0</span></div>
<div>进度: <span id="progress">0</span>/<span id="total">5</span></div>
</div>
<h1>AI语文拼音游戏</h1>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="question-area">
<div class="question" id="questionText">准备开始...</div>
<div class="options" id="optionsContainer">
<!-- 选项将通过JavaScript动态生成 -->
</div>
</div>
</div>
<div class="message" id="message">
<h2 id="messageTitle">标题</h2>
<p id="messageText">内容</p>
<button class="message-btn" id="messageBtn">继续</button>
</div>
<script>
// DOM元素
const questionText = document.getElementById("questionText");
const optionsContainer = document.getElementById("optionsContainer");
const message = document.getElementById("message");
const messageTitle = document.getElementById("messageTitle");
const messageText = document.getElementById("messageText");
const messageBtn = document.getElementById("messageBtn");
const scoreElement = document.getElementById("score");
const progressElement = document.getElementById("progress");
const totalElement = document.getElementById("total");
const progressFill = document.getElementById("progressFill");
// 游戏状态
let currentGame = null;
let currentQuestionIndex = 0;
let score = 0;
let correctCount = 0;
let gameStarted = false;
let gameId = "ai_language_pinyin_" + Date.now();
// 初始化AI游戏生成器
async function initAIGame() {
try {
if (!window.aiGameGenerator) {
throw new Error("AI游戏生成器未加载");
}
await window.aiGameGenerator.init();
console.log("✅ AI游戏生成器初始化成功");
// 生成语文拼音游戏
currentGame = window.aiGameGenerator.generatePersonalizedGame(
"language",
"quiz",
5
);
if (currentGame && currentGame.questions.length > 0) {
// 筛选拼音题目
const pinyinQuestions = currentGame.questions.filter(
(q) => q.question.includes("拼音") || q.question.includes("声调")
);
if (pinyinQuestions.length > 0) {
currentGame.questions = pinyinQuestions.slice(0, 5);
}
totalElement.textContent = currentGame.questions.length;
console.log("🎮 AI语文拼音游戏生成成功:", currentGame);
return true;
} else {
throw new Error("无法生成游戏题目");
}
} catch (error) {
console.error("❌ AI游戏初始化失败:", error);
return false;
}
}
// 显示当前题目
function showCurrentQuestion() {
if (
!currentGame ||
currentQuestionIndex >= currentGame.questions.length
) {
endGame();
return;
}
const question = currentGame.questions[currentQuestionIndex];
questionText.textContent = question.question;
// 清空选项容器
optionsContainer.innerHTML = "";
// 创建选项按钮
question.options.forEach((option, index) => {
const button = document.createElement("button");
button.className = "option-btn";
button.textContent = option;
button.onclick = () => selectAnswer(index, question);
optionsContainer.appendChild(button);
});
// 更新进度
progressElement.textContent = currentQuestionIndex + 1;
progressFill.style.width = `${
((currentQuestionIndex + 1) / currentGame.questions.length) * 100
}%`;
}
// 选择答案
function selectAnswer(selectedIndex, question) {
if (message.classList.contains("show")) return;
const isCorrect = selectedIndex === question.correct;
const selectedButton = optionsContainer.children[selectedIndex];
const correctButton = optionsContainer.children[question.correct];
// 显示答案效果
selectedButton.classList.add(isCorrect ? "correct" : "wrong");
if (!isCorrect) {
correctButton.classList.add("correct");
}
// 虚拟老师反馈
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.stopAllSpeech();
setTimeout(() => {
if (isCorrect) {
window.gameVirtualTeacher.recordCorrect();
} else {
window.gameVirtualTeacher.recordIncorrect();
}
}, 300);
}
// 更新分数
if (isCorrect) {
correctCount++;
score += 10;
scoreElement.textContent = score;
}
// 记录游戏数据
if (gameStarted && window.gameTracker) {
if (isCorrect) {
window.gameTracker.recordCorrect(10, {
question: question.question,
selected: question.options[selectedIndex],
correct: question.options[question.correct],
questionNumber: currentQuestionIndex + 1,
});
} else {
window.gameTracker.recordIncorrect(0, {
question: question.question,
selected: question.options[selectedIndex],
correct: question.options[question.correct],
questionNumber: currentQuestionIndex + 1,
});
}
}
// 显示结果消息
const messageText = isCorrect
? `太棒了!${question.question} 的答案是 ${
question.options[question.correct]
}`
: `再想想!正确答案是 ${question.options[question.correct]}`;
showMessage(isCorrect, messageText);
if (isCorrect) {
createConfetti();
}
}
// 显示消息
function showMessage(isCorrect, text) {
message.className = "message " + (isCorrect ? "correct" : "wrong");
messageTitle.textContent = isCorrect ? "太棒了!" : "再试一次";
messageText.textContent = text;
message.classList.add("show");
}
// 创建彩色纸屑效果
function createConfetti() {
const colors = [
"#FF9AA2",
"#FFB7B2",
"#FFDAC1",
"#E2F0CB",
"#B5EAD7",
"#C7CEEA",
];
for (let i = 0; i < 50; i++) {
const confetti = document.createElement("div");
confetti.className = "confetti";
confetti.style.left = `${Math.random() * 100}%`;
confetti.style.backgroundColor =
colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = `${Math.random() * 10 + 5}px`;
confetti.style.height = `${Math.random() * 10 + 5}px`;
confetti.style.animation = `confetti-fall ${
Math.random() * 2 + 2
}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
document.body.appendChild(confetti);
setTimeout(() => {
confetti.remove();
}, 3000);
}
}
// 下一题
function nextQuestion() {
message.classList.remove("show");
currentQuestionIndex++;
showCurrentQuestion();
}
// 结束游戏
function endGame() {
const successRate = (correctCount / currentGame.questions.length) * 100;
message.className = "message correct";
messageTitle.textContent = "游戏完成!";
messageText.textContent = `恭喜你完成了游戏!\n得分: ${score}\n正确率: ${successRate.toFixed(
1
)}%`;
message.classList.add("show");
// 虚拟老师游戏结束
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameEnd();
}
// 记录游戏结果
if (gameStarted && window.gameTracker) {
if (successRate >= 80) {
window.gameTracker.recordWin(score, {
totalQuestions: currentGame.questions.length,
correctCount: correctCount,
successRate: successRate,
});
} else {
window.gameTracker.recordLose(score, {
totalQuestions: currentGame.questions.length,
correctCount: correctCount,
successRate: successRate,
});
}
}
messageBtn.textContent = "重新开始";
messageBtn.onclick = restartGame;
}
// 重新开始游戏
function restartGame() {
currentQuestionIndex = 0;
score = 0;
correctCount = 0;
scoreElement.textContent = "0";
progressElement.textContent = "0";
progressFill.style.width = "0%";
message.classList.remove("show");
messageBtn.textContent = "继续";
messageBtn.onclick = nextQuestion;
showCurrentQuestion();
}
// 事件监听
messageBtn.addEventListener("click", nextQuestion);
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", async function () {
// 初始化虚拟老师
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher
.init({
intro:
"欢迎来到AI语文拼音游戏我会帮你学习拼音和声调准备好了吗",
})
.then(() => {
console.log("🦉 AI语文拼音游戏虚拟老师初始化成功");
})
.catch((error) => {
console.error("❌ 虚拟老师初始化失败:", error);
});
}
// 初始化后端集成
Promise.all([window.userManager.init(), window.dataManager.init()])
.then(async () => {
console.log("后端集成初始化完成");
// 初始化AI游戏
const success = await initAIGame();
if (success) {
// 开始游戏跟踪
if (window.gameTracker) {
window.gameTracker.startGame(gameId, {
gameType: "ai_language_pinyin",
difficulty: "adaptive",
});
}
// 虚拟老师游戏开始
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameStart("AI语文拼音游戏");
setTimeout(() => {
window.gameVirtualTeacher.speak(
"欢迎来到AI语文拼音游戏我会帮你学习拼音和声调准备好了吗"
);
}, 1000);
}
gameStarted = true;
showCurrentQuestion();
} else {
showMessage(false, "游戏初始化失败,请刷新页面重试");
}
})
.catch((error) => {
console.error("后端集成初始化失败:", error);
showMessage(false, "系统初始化失败,请刷新页面重试");
});
});
</script>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
rg-09112127/html/play/img/.DS_Store vendored Normal file

Binary file not shown.

BIN
rg-09112127/html/play/img/1/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 KiB

BIN
rg-09112127/html/play/img/2/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 KiB

BIN
rg-09112127/html/play/img/3/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
rg-09112127/html/play/img/4/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
rg-09112127/html/play/img/5/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -0,0 +1,372 @@
<!DOCTYPE html>
<html>
<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>
body {
font-family: 'Comic Sans MS', cursive, sans-serif;
background-color: #e8f5e9;
text-align: center;
padding: 20px;
}
.game-container {
max-width: 900px;
margin: 0 auto;
background-color: white;
border-radius: 20px;
padding: 20px;
box-shadow: 0 0 15px rgba(0,0,0,0.1);
}
h1 {
color: #2e7d32;
font-size: 28px;
}
.zoo-section {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 20px 0;
}
.animal-pen {
width: 200px;
margin: 10px;
padding: 15px;
background-color: #f1f8e9;
border-radius: 15px;
position: relative;
}
.animal-pen h3 {
margin-top: 0;
color: #1b5e20;
}
.animal {
display: inline-block;
margin: 5px;
cursor: pointer;
transition: transform 0.2s;
}
.animal:hover {
transform: scale(1.1);
}
.animal img {
width: 60px;
height: 60px;
}
.add-animal, .remove-animal {
background-color: #4CAF50;
color: white;
border: none;
padding: 5px 10px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
}
.remove-animal {
background-color: #f44336;
}
.problem-section {
margin: 20px 0;
padding: 15px;
background-color: #c8e6c9;
border-radius: 15px;
}
.problem {
font-size: 20px;
margin-bottom: 10px;
}
.answer-input {
font-size: 18px;
padding: 8px;
width: 60px;
text-align: center;
}
.submit-btn {
background-color: #2e7d32;
color: white;
border: none;
padding: 8px 15px;
margin-left: 10px;
border-radius: 5px;
cursor: pointer;
}
.feedback {
font-size: 24px;
font-weight: bold;
margin: 15px 0;
min-height: 30px;
color: #d84315;
}
.comparison-section {
margin: 20px 0;
padding: 15px;
background-color: #dcedc8;
border-radius: 15px;
}
.comparison-btn {
background-color: #689f38;
color: white;
border: none;
padding: 10px 15px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
.celebration {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255,255,255,0.9);
display: none;
justify-content: center;
align-items: center;
flex-direction: column;
z-index: 100;
}
.celebration h2 {
font-size: 40px;
color: #d84315;
margin-bottom: 20px;
}
.celebration img {
width: 150px;
height: 150px;
animation: bounce 0.5s infinite alternate;
}
@keyframes bounce {
from { transform: translateY(0); }
to { transform: translateY(-20px); }
}
.animal-count {
font-weight: bold;
font-size: 18px;
color:
#1b5e20;
}
</style>
</head>
<body>
<div class="game-container">
<h1>🐘 小小动物园数学探险 🦁</h1>
<div class="problem-section">
<div class="problem">园长的问题:<span id="problem-text">2 + 1</span> = ?</div>
<input type="number" class="answer-input" id="answer-input" min="0" max="5">
<button class="submit-btn" id="submit-btn">提交</button>
<div id="math-feedback" class="feedback"></div>
</div>
<div class="zoo-section">
<div class="animal-pen" id="lion-pen">
<h3>小猫馆 🦁</h3>
<div class="animal-count">数量: <span id="lion-count">0</span></div>
<div id="lion-container"></div>
<button class="add-animal" data-pen="lion">添加猫</button>
<button class="remove-animal" data-pen="lion">减少猫</button>
</div>
<div class="animal-pen" id="elephant-pen">
<h3>大象馆 🐘</h3>
<div class="animal-count">数量: <span id="elephant-count">0</span></div>
<div id="elephant-container"></div>
<button class="add-animal" data-pen="elephant">添加大象</button>
<button class="remove-animal" data-pen="elephant">减少大象</button>
</div>
<div class="animal-pen" id="monkey-pen">
<h3>猴子馆 🐵</h3>
<div class="animal-count">数量: <span id="monkey-count">0</span></div>
<div id="monkey-container"></div>
<button class="add-animal" data-pen="monkey">添加猴子</button>
<button class="remove-animal" data-pen="monkey">减少猴子</button>
</div>
<div class="animal-pen" id="panda-pen">
<h3>熊猫馆 🐼</h3>
<div class="animal-count">数量: <span id="panda-count">0</span></div>
<div id="panda-container"></div>
<button class="add-animal" data-pen="panda">添加熊猫</button>
<button class="remove-animal" data-pen="panda">减少熊猫</button>
</div>
</div>
<div class="comparison-section">
<h2>比一比,哪个多?</h2>
<button class="comparison-btn" data-compare="lion-elephant">猫 🦁 vs 大象 🐘</button>
<button class="comparison-btn" data-compare="lion-monkey">猫 🦁 vs 猴子 🐵</button>
<button class="comparison-btn" data-compare="elephant-panda">大象 🐘 vs 熊猫 🐼</button>
<button class="comparison-btn" data-compare="monkey-panda">猴子 🐵 vs 熊猫 🐼</button>
<div id="comparison-result" class="feedback"></div>
</div>
</div>
<div class="celebration" id="celebration">
<h2>太棒了!答对了!</h2>
<img src="123.jpg" alt="庆祝">
<button class="submit-btn" onclick  ="hideCelebration()">继续探险</button>
</div>
<script>
// 动物数据
const animals = {
lion: { name: "猫", emoji: "🦁", img: "456.jpg", count: 0 },
elephant: { name: "大象", emoji: "🐘", img: "789.jpg", count: 0 },
monkey: { name: "猴子", emoji: "🐵", img: "0.jpg", count: 0 },
panda: { name: "熊猫", emoji: "🐼", img: "7.jpg", count: 0 }
};
// 当前数学问题
let currentProblem = generateProblem();
document.getElementById('problem-text').textContent = currentProblem.text;
// 添加动物按钮事件
document.querySelectorAll('.add-animal').forEach(btn => {
btn.addEventListener('click', function() {
const pen = this.getAttribute('data-pen');
if (animals[pen].count < 5) {
animals[pen].count++;
// 详细数据打印
console.log('🎯 数字探险馆游戏 - 添加动物记录');
console.log('📊 操作信息:', {
操作类型: '添加动物',
动物类型: animals[pen].name,
当前数量: animals[pen].count,
操作时间: new Date().toLocaleString('zh-CN')
});
updatePen(pen);
}
});
});
// 减少动物按钮事件
document.querySelectorAll('.remove-animal').forEach(btn => {
btn.addEventListener('click', function() {
const pen = this.getAttribute('data-pen');
if (animals[pen].count > 0) {
animals[pen].count--;
// 详细数据打印
console.log('🎯 数字探险馆游戏 - 减少动物记录');
console.log('📊 操作信息:', {
操作类型: '减少动物',
动物类型: animals[pen].name,
当前数量: animals[pen].count,
操作时间: new Date().toLocaleString('zh-CN')
});
updatePen(pen);
}
});
});
// 更新围栏显示
function updatePen(pen) {
const container = document.getElementById(`${pen}-container`);
const countElement = document.getElementById(`${pen}-count`);
container.innerHTML = '';
countElement.textContent = animals[pen].count;
// 添加动物图片
for (let i = 0; i < animals[pen].count; i++) {
const animal = document.createElement('div');
animal.className = 'animal';
animal.innerHTML = `<img src="${animals[pen].img}" alt="${animals[pen].name}">`;
container.appendChild(animal);
}
}
// 比较按钮事件
document.querySelectorAll('.comparison-btn').forEach(btn => {
btn.addEventListener('click', function() {
const [pen1, pen2] = this.getAttribute('data-compare').split('-');
const count1 = animals[pen1].count;
const count2 = animals[pen2].count;
let result = '';
if (count1 > count2) {
result = `${animals[pen1].name}${animals[pen1].emoji}${animals[pen2].name}${animals[pen2].emoji}多,多${count1 - count2}`;
} else if (count2 > count1) {
result = `${animals[pen2].name}${animals[pen2].emoji}${animals[pen1].name}${animals[pen1].emoji}多,多${count2 - count1}`;
} else {
result = `两种动物数量一样多,都是${count1}`;
}
document.getElementById('comparison-result').textContent = result;
});
});
// 数学问题提交
document.getElementById('submit-btn').addEventListener('click', function() {
const userAnswer = parseInt(document.getElementById('answer-input').value);
if (isNaN(userAnswer)) {
document.getElementById('math-feedback').textContent = '请输入一个数字';
return;
}
// 详细数据打印
console.log('🎯 数字探险馆游戏 - 数学问题提交记录');
console.log('📊 问题信息:', {
问题内容: currentProblem.text,
正确答案: currentProblem.answer,
用户答案: userAnswer,
是否正确: userAnswer === currentProblem.answer ? '✅ 正确' : '❌ 错误',
提交时间: new Date().toLocaleString('zh-CN')
});
if (userAnswer === currentProblem.answer) {
document.getElementById('math-feedback').textContent = '答对了!你真棒!';
showCelebration();
// 生成新问题
setTimeout(() => {
currentProblem = generateProblem();
document.getElementById('problem-text').textContent = currentProblem.text;
document.getElementById('answer-input').value = '';
document.getElementById('math-feedback').textContent = '';
}, 1500);
} else {
document.getElementById('math-feedback').textContent = '再试试看!';
}
});
// 生成数学问题
function generateProblem() {
const num1 = Math.floor(Math.random() * 3) + 1; // 1-3
const num2 = Math.floor(Math.random() * 3) + 1; // 1-3
const answer = num1 + num2;
return {
text: `${num1} + ${num2}`,
answer: answer
};
}
// 显示庆祝动画
function showCelebration() {
document.getElementById('celebration').style.display = 'flex';
}
function hideCelebration() {
document.getElementById('celebration').style.display = 'none';
}
</script>
</body>
</html>

View File

@@ -0,0 +1,709 @@
<!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/virtualTeacher.js"></script>
<script src="../../js/gameVirtualTeacher.js"></script>
<!-- 引入体感交互脚本 -->
<script src="../../js/directBodySensation.js"></script>
<style>
:root {
--primary: #ff9aa2;
--secondary: #ffb7b2;
--accent: #ffdac1;
--correct: #b5ead7;
--wrong: #ff9aa2;
--button: #70a1ff;
--text: #5e5346;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Comic Sans MS", "Marker Felt", "微软雅黑", sans-serif;
background-color: #f9f7f0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-image: radial-gradient(circle, #f5f5f5 10%, transparent 10%);
background-size: 30px 30px;
overflow: hidden;
}
.game-container {
width: 80%;
background-color: white;
border-radius: 20px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
text-align: center;
position: relative;
overflow: hidden;
border: 5px solid #ffdac1;
}
h1 {
color: #ff6b6b;
margin-bottom: 30px;
font-size: 5rem;
text-shadow: 3px 3px 0 #ffdac1;
letter-spacing: 2px;
}
.game-area {
display: flex;
justify-content: space-around;
margin: 30px 0;
}
.math-card {
width: 45%;
padding: 20px;
background-color: #f0f8ff;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
position: relative;
transition: all 0.3s ease;
}
.math-card:hover,
.math-card.active {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
.math-card::before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
border: 3px dashed #ffb7b2;
border-radius: 20px;
z-index: -1;
opacity: 0.5;
}
.equation {
font-size: 5rem;
margin: 20px 0;
color: #5e5346;
font-weight: bold;
}
.select-btn {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: var(--button);
color: white;
border: none;
font-size: 2rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 5px 0 #4a6baf;
transition: all 0.2s ease;
margin-top: 10px;
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
}
.select-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
.select-btn:active {
transform: translateY(5px);
box-shadow: 0 2px 0 #4a6baf;
}
.message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
background-color: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
z-index: 100;
text-align: center;
max-width: 80%;
transition: all 0.3s ease;
border: 5px solid;
}
.message.show {
transform: translate(-50%, -50%) scale(1);
}
.message.correct {
border-color: #b5ead7;
background-color: #e8f8f3;
}
.message.wrong {
border-color: #ff9aa2;
background-color: #ffeef0;
}
.message h2 {
font-size: 3rem;
margin-bottom: 15px;
}
.message p {
font-size: 2rem;
margin-bottom: 20px;
}
.message-btn {
padding: 10px 20px;
border-radius: 50px;
border: none;
background-color: var(--button);
color: white;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s ease;
}
.message-btn:hover {
background-color: #5d8eff;
transform: scale(1.05);
}
/* 体感交互视频样式 */
.body-sensation-container {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 20px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
z-index: 1000;
max-width: 600px;
}
.body-video-feed {
position: relative;
width: 500px;
height: 350px;
border-radius: 10px;
overflow: hidden;
margin-bottom: 15px;
}
.body-video-feed img {
width: 100%;
height: 100%;
object-fit: cover;
}
.body-status-overlay {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 15px;
border-radius: 8px;
font-size: 14px;
line-height: 1.3;
}
.body-instruction {
text-align: center;
font-size: 18px;
color: #333;
font-weight: 500;
padding: 8px;
}
/* 体感交互容器样式用于directBodySensation.js */
.box-body {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 20px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
z-index: 2000;
max-width: 500px;
text-align: center;
}
.box-body img {
max-width: 100%;
height: auto;
border-radius: 10px;
margin: 10px 0;
}
.box-body div {
margin: 10px 0;
padding: 5px;
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
z-index: 90;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
@keyframes jump {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-30px);
}
}
@media (max-width: 600px) {
.game-area {
flex-direction: column;
align-items: center;
}
.math-card {
width: 90%;
margin-bottom: 20px;
}
h1 {
font-size: 5rem;
}
.equation {
font-size: 5rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>比大小(选择大的)</h1>
<div class="game-area">
<div class="math-card" id="leftCard">
<div class="equation" id="leftEquation">1+1</div>
<button class="select-btn" id="leftBtn">选择</button>
</div>
<div class="math-card" id="rightCard">
<div class="equation" id="rightEquation">2+2</div>
<button class="select-btn" id="rightBtn">选择</button>
</div>
</div>
</div>
<div class="message" id="message">
<h2 id="messageTitle">标题</h2>
<p id="messageText">内容</p>
<button class="message-btn" id="messageBtn">继续</button>
</div>
<script>
// DOM元素
const leftEquation = document.getElementById("leftEquation");
const rightEquation = document.getElementById("rightEquation");
const leftBtn = document.getElementById("leftBtn");
const rightBtn = document.getElementById("rightBtn");
const message = document.getElementById("message");
const messageTitle = document.getElementById("messageTitle");
const messageText = document.getElementById("messageText");
const messageBtn = document.getElementById("messageBtn");
// 体感交互元素
const bodySensationContainer = document.getElementById(
"bodySensationContainer"
);
const bodyVideoFeed = document.getElementById("bodyVideoFeed");
const bodyConnectionStatus = document.getElementById(
"bodyConnectionStatus"
);
const bodyHandStatus = document.getElementById("bodyHandStatus");
const bodyInstruction = document.getElementById("bodyInstruction");
// 游戏状态
let leftValue = 0;
let rightValue = 0;
let correctAnswer = "";
let score = 0;
let correctCount = 0;
let totalQuestions = 0;
let gameStarted = false;
let gameId = 2; // 比大小游戏ID
// 体感交互控制函数
function showBodyInteraction() {
if (bodySensationContainer) {
bodySensationContainer.style.display = "block";
}
// 启动体感交互系统
if (typeof showBody === "function") {
showBody();
}
}
function hideBodyInteraction() {
if (bodySensationContainer) {
bodySensationContainer.style.display = "none";
}
}
function updateBodyInstruction(text) {
if (bodyInstruction) {
bodyInstruction.textContent = text;
}
}
// 生成5以内的加减法
function generateEquation() {
const operations = ["+", "-"];
const op = operations[Math.floor(Math.random() * operations.length)];
let a, b, result;
do {
a = Math.floor(Math.random() * 5) + 1; // 1-5
b = Math.floor(Math.random() * 5) + 1; // 1-5
if (op === "+") {
result = a + b;
} else {
result = a - b;
// 确保结果不小于0
if (result < 0) {
[a, b] = [b, a]; // 交换a和b
result = a - b;
}
}
} while (result > 5); // 确保结果不超过5
return {
equation: `${a}${op}${b}`,
value: result,
};
}
// 生成新题目
function generateNewQuestion(type) {
// 清除默认样式
document.querySelectorAll(".math-card")[0].className = "math-card";
document.querySelectorAll(".math-card")[1].className = "math-card";
if (type == "init") {
// 初始化游戏状态
score = 0;
correctCount = 0;
totalQuestions = 0;
gameStarted = true;
// 虚拟老师游戏开始
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher.gameStart("比大小游戏");
}
// 开始游戏跟踪
if (window.gameTracker) {
window.gameTracker.startGame(gameId, {
gameType: "compare_size",
difficulty: "easy",
});
}
// 打开窗口
iframePostMessage();
}
const left = generateEquation();
const right = generateEquation();
leftEquation.textContent = left.equation;
rightEquation.textContent = right.equation;
leftValue = left.value;
rightValue = right.value;
// 显示体感交互视频
showBodyInteraction();
// 更新体感交互提示文本
updateBodyInstruction(
`请举起左手选择${left.equation}或举起右手选择${right.equation}`
);
correctAnswer =
leftValue > rightValue
? "left"
: rightValue > leftValue
? "right"
: "equal";
}
// 显示消息
function showMessage(isCorrect, text) {
message.className = "message " + (isCorrect ? "correct" : "wrong");
messageTitle.textContent = isCorrect ? "太棒了!" : "再试一次";
messageText.textContent = text;
message.classList.add("show");
if (isCorrect) {
createConfetti();
}
}
// 创建彩色纸屑效果
function createConfetti() {
const colors = [
"#FF9AA2",
"#FFB7B2",
"#FFDAC1",
"#E2F0CB",
"#B5EAD7",
"#C7CEEA",
];
for (let i = 0; i < 50; i++) {
const confetti = document.createElement("div");
confetti.className = "confetti";
confetti.style.left = `${Math.random() * 100}%`;
confetti.style.backgroundColor =
colors[Math.floor(Math.random() * colors.length)];
confetti.style.width = `${Math.random() * 10 + 5}px`;
confetti.style.height = `${Math.random() * 10 + 5}px`;
confetti.style.animation = `confetti-fall ${
Math.random() * 2 + 2
}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
document.body.appendChild(confetti);
setTimeout(() => {
confetti.remove();
}, 3000);
}
}
// 检查答案
function checkAnswer(selectedSide) {
console.log(
"checkAnswer message",
document.getElementById("message"),
document.getElementById("message").classList.contains("show")
);
if (document.getElementById("message").classList.contains("show")) {
return;
}
// 隐藏体感交互按钮
hideBodyInteraction();
let isCorrect = false;
let message = "";
document.querySelectorAll(".math-card")[
selectedSide == "left" ? 0 : 1
].className = "math-card active";
if (correctAnswer === "equal") {
isCorrect = true;
message = "两边一样大!";
} else if (selectedSide === correctAnswer) {
isCorrect = true;
message = `对了!${leftValue} ${
selectedSide === "left" ? ">" : "<"
} ${rightValue}`;
} else {
isCorrect = false;
message = `不对哦!${leftValue} ${
correctAnswer === "left" ? ">" : "<"
} ${rightValue}`;
}
// 虚拟老师反馈
if (window.gameVirtualTeacher) {
// 立即停止当前语音
window.gameVirtualTeacher.stopAllSpeech();
// 延迟一点再播放反馈语音
setTimeout(() => {
if (isCorrect) {
window.gameVirtualTeacher.recordCorrect();
} else {
window.gameVirtualTeacher.recordIncorrect();
}
}, 300);
}
// 详细数据打印
console.log("🎯 比大小游戏 - 用户点击记录");
console.log("📊 问题信息:", {
问题内容: `${leftValue} vs ${rightValue}`,
左侧值: leftValue,
右侧值: rightValue,
正确答案: correctAnswer,
用户选择: selectedSide,
是否正确: isCorrect ? "✅ 正确" : "❌ 错误",
});
console.log("📈 游戏进度:", {
当前得分: score,
正确次数: correctCount,
总问题数: totalQuestions + 1,
正确率:
totalQuestions > 0
? `${((correctCount / (totalQuestions + 1)) * 100).toFixed(1)}%`
: "0%",
});
console.log("⏰ 时间信息:", {
回答时间: new Date().toLocaleString("zh-CN"),
游戏时长: window.gameTracker
? window.gameTracker.getCurrentPlayTime() + "秒"
: "未知",
});
// 记录游戏结果
if (gameStarted && window.gameTracker) {
totalQuestions++;
if (isCorrect) {
correctCount++;
score += 10;
window.gameTracker.recordCorrect(10, {
question: `${leftValue} vs ${rightValue}`,
selected: selectedSide,
correct: correctAnswer,
leftValue: leftValue,
rightValue: rightValue,
questionNumber: totalQuestions,
});
} else {
window.gameTracker.recordIncorrect(0, {
question: `${leftValue} vs ${rightValue}`,
selected: selectedSide,
correct: correctAnswer,
leftValue: leftValue,
rightValue: rightValue,
questionNumber: totalQuestions,
});
}
}
showMessage(isCorrect, message);
}
// 事件监听
leftBtn.addEventListener("click", (event) => checkAnswer("left"));
rightBtn.addEventListener("click", (event) => checkAnswer("right"));
messageBtn.addEventListener("click", () => {
message.classList.remove("show");
generateNewQuestion("continue");
});
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", function () {
// 初始化虚拟老师
if (window.gameVirtualTeacher) {
window.gameVirtualTeacher
.init({
intro: "欢迎来到比大小游戏!我会帮你比较数字的大小,准备好了吗?",
})
.then(() => {
console.log("🦉 比大小游戏虚拟老师初始化成功");
// 延迟播放游戏介绍,避免与访问跟踪语音冲突
setTimeout(() => {
window.gameVirtualTeacher.speak(
"欢迎来到比大小游戏!我会帮你比较数字的大小,准备好了吗?"
);
}, 1000);
})
.catch((error) => {
console.error("❌ 虚拟老师初始化失败:", error);
});
}
// 初始化后端集成
Promise.all([window.userManager.init(), window.dataManager.init()])
.then(() => {
console.log("后端集成初始化完成");
// 初始化游戏
generateNewQuestion("init");
})
.catch((error) => {
console.error("后端集成初始化失败:", error);
// 即使后端初始化失败,也可以开始游戏
generateNewQuestion("init");
});
});
// 网页间相互通信
window.addEventListener("message", function (event) {
// 检查消息来源是否可信
if (event.origin !== "http://localhost") return;
const message = event.data;
console.log("iframe 接收到的数据:", message);
if (message.type == "语音识别") {
} else if (message.type == "体感识别") {
if (message.data.indexOf("左手") !== -1) {
checkAnswer("left");
} else if (message.data.indexOf("右手") !== -1) {
checkAnswer("right");
} else if (message.data.indexOf("双手") !== -1) {
messageBtn.click();
}
}
});
function iframePostMessage() {
const message = { type: "体感识别", status: "request" };
window.parent.postMessage(message, "http://localhost"); // 替换为目标域名
}
// 页面销毁时,关闭体感采集
window.onbeforeunload = function (event) {
iframePostMessage();
};
</script>
</body>
</html>

View File

@@ -0,0 +1,293 @@
<!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="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 引入后端集成脚本 -->
<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>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3B82F6',
secondary: '#EC4899',
success: '#10B981',
danger: '#EF4444',
},
}
}
}
</script>
</head>
<body class="bg-gradient-to-br from-green-50 to-yellow-50 min-h-screen font-sans">
<div class="container mx-auto px-4 py-8 max-w-3xl">
<header class="text-center mb-6">
<h1 class="text-3xl font-bold text-primary mb-2">水果数字比较大闯关</h1>
<p class="text-neutral">选择正确的比较符号</p>
</header>
<main class="bg-white rounded-xl shadow-lg p-6 mb-8">
<div class="flex justify-between mb-6">
<div class="bg-primary/10 rounded-lg p-2">
<span class="font-bold">得分: <span id="score">0</span></span>
</div>
<div class="bg-secondary/10 rounded-lg p-2">
<span class="font-bold">关卡: <span id="level">1</span></span>
</div>
<button id="toggle-voice" class="bg-gray-200 hover:bg-gray-300 p-2 rounded-full shadow-sm">
<i class="fa fa-volume-up text-gray-600"></i>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<div id="left-card" class="bg-green-50 rounded-lg p-4 shadow-md border-2 border-green-200">
<div class="text-center text-xl font-bold text-green-600 mb-3">左边</div>
<div id="left-fruits" class="grid grid-cols-3 gap-2 justify-items-center mb-3"></div>
<div class="text-center text-2xl font-bold" id="left-number">?</div>
</div>
<div id="right-card" class="bg-orange-50 rounded-lg p-4 shadow-md border-2 border-orange-200">
<div class="text-center text-xl font-bold text-orange-600 mb-3">右边</div>
<div id="right-fruits" class="grid grid-cols-3 gap-2 justify-items-center mb-3"></div>
<div class="text-center text-2xl font-bold" id="right-number">?</div>
</div>
</div>
<div class="flex justify-center gap-3 mb-6">
<button id="less-than"
class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-6 rounded-full shadow-md">
<i class="fa fa-chevron-left"></i>
</button>
<button id="equal"
class="bg-purple-500 hover:bg-purple-600 text-white font-bold py-2 px-6 rounded-full shadow-md">
=
</button>
<button id="greater-than"
class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-6 rounded-full shadow-md">
<i class="fa fa-chevron-right"></i>
</button>
</div>
<div id="feedback" class="text-center text-xl font-bold h-8 mb-6"></div>
<div class="flex justify-center gap-4">
<button id="start-game"
class="bg-primary hover:bg-primary/90 text-white font-bold py-2 px-6 rounded-full shadow-md flex items-center justify-center">
<i class="fa fa-play-circle mr-2"></i> 开始游戏
</button>
<button id="reset-game"
class="bg-neutral hover:bg-neutral/90 text-white font-bold py-2 px-6 rounded-full shadow-md opacity-50 cursor-not-allowed flex items-center justify-center"
disabled>
<i class="fa fa-refresh mr-2"></i> 重新开始
</button>
</div>
</main>
<div id="level-up" class="fixed inset-0 bg-black/50 flex items-center justify-center z-10 hidden">
<div class="bg-white rounded-xl p-6 max-w-md w-full text-center">
<h2 class="text-2xl font-bold text-primary mb-4">恭喜晋级!</h2>
<p class="text-lg mb-6">你已晋级到第 <span id="new-level">2</span> 关!</p>
<button id="continue-btn"
class="bg-primary hover:bg-primary/90 text-white font-bold py-2 px-6 rounded-full shadow-md">
继续
</button>
</div>
</div>
</div>
<script>
const fruits = ['🍎', '🍌', '🍊', '🍇', '🍓', '🍉'];
const fruitNames = ['苹果', '香蕉', '橙子', '葡萄', '草莓', '西瓜'];
let gameState = {
score: 0,
level: 1,
maxNum: 5,
active: false,
left: 0,
right: 0,
currentFruit: 0,
voiceEnabled: true
};
function init() {
document.getElementById('start-game').addEventListener('click', startGame);
document.getElementById('reset-game').addEventListener('click', resetGame);
document.getElementById('less-than').addEventListener('click', () => checkAnswer('<'));
document.getElementById('equal').addEventListener('click', () => checkAnswer('='));
document.getElementById('greater-than').addEventListener('click', () => checkAnswer('>'));
document.getElementById('continue-btn').addEventListener('click', () => {
document.getElementById('level-up').classList.add('hidden');
generateNumbers();
});
document.getElementById('toggle-voice').addEventListener('click', toggleVoice);
}
function toggleVoice() {
gameState.voiceEnabled = !gameState.voiceEnabled;
const icon = document.getElementById('toggle-voice').querySelector('i');
if (gameState.voiceEnabled) {
icon.className = 'fa fa-volume-up text-gray-600';
} else {
icon.className = 'fa fa-volume-off text-gray-600';
}
}
function speak(text) {
if (!gameState.voiceEnabled) return;
if ('speechSynthesis' in window) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'zh-CN';
utterance.rate = 0.9; // 稍微慢一点,便于儿童理解
speechSynthesis.speak(utterance);
}
}
function startGame() {
speak("请比较左右两边的水果数量,选择正确的比较符号。");
gameState.active = true;
document.getElementById('start-game').disabled = true;
document.getElementById('reset-game').disabled = false;
document.getElementById('start-game').classList.add('opacity-50');
document.getElementById('reset-game').classList.remove('opacity-50');
generateNumbers();
}
function resetGame() {
gameState = {
score: 0,
level: 1,
maxNum: 5,
active: false,
left: 0,
right: 0,
currentFruit: 0,
voiceEnabled: gameState.voiceEnabled
};
document.getElementById('score').textContent = '0';
document.getElementById('level').textContent = '1';
document.getElementById('left-number').textContent = '?';
document.getElementById('right-number').textContent = '?';
document.getElementById('left-fruits').innerHTML = '';
document.getElementById('right-fruits').innerHTML = '';
document.getElementById('feedback').textContent = '';
document.getElementById('start-game').disabled = false;
document.getElementById('reset-game').disabled = true;
document.getElementById('start-game').classList.remove('opacity-50');
document.getElementById('reset-game').classList.add('opacity-50');
document.getElementById('level-up').classList.add('hidden');
speak("游戏已重置,点击开始游戏按钮重新开始。");
}
function generateNumbers() {
gameState.currentFruit = Math.floor(Math.random() * fruits.length);
gameState.left = Math.floor(Math.random() * gameState.maxNum) + 1;
gameState.right = Math.floor(Math.random() * gameState.maxNum) + 1;
document.getElementById('left-number').textContent = gameState.left;
document.getElementById('right-number').textContent = gameState.right;
renderFruits('left-fruits', gameState.left);
renderFruits('right-fruits', gameState.right);
document.getElementById('feedback').textContent = '';
document.getElementById('left-card').classList.remove('border-success', 'border-danger');
document.getElementById('right-card').classList.remove('border-success', 'border-danger');
document.getElementById('left-card').classList.add('border-green-200');
document.getElementById('right-card').classList.add('border-orange-200');
// 语音提示题目
const fruitName = fruitNames[gameState.currentFruit];
speak(`左边有${gameState.left}${fruitName},右边有${gameState.right}${fruitName},哪个更多?`);
}
function renderFruits(containerId, count) {
const container = document.getElementById(containerId);
container.innerHTML = '';
const fruit = fruits[gameState.currentFruit];
for (let i = 0; i < count; i++) {
const div = document.createElement('div');
div.className = 'text-3xl';
div.textContent = fruit;
container.appendChild(div);
}
}
function checkAnswer(operator) {
if (!gameState.active) return;
let isCorrect = false;
switch (operator) {
case '<':
isCorrect = gameState.left < gameState.right;
break;
case '=':
isCorrect = gameState.left === gameState.right;
break;
case '>':
isCorrect = gameState.left > gameState.right;
break;
}
const feedback = document.getElementById('feedback');
const leftCard = document.getElementById('left-card');
const rightCard = document.getElementById('right-card');
if (isCorrect) {
gameState.score++;
document.getElementById('score').textContent = gameState.score;
feedback.textContent = '🎉 答对了!真棒!';
feedback.className = 'text-success';
leftCard.classList.remove('border-green-200', 'border-danger');
rightCard.classList.remove('border-orange-200', 'border-danger');
leftCard.classList.add('border-success');
rightCard.classList.add('border-success');
speak("答对了!真棒!");
if (gameState.score % 5 === 0) {
setTimeout(levelUp, 1500);
return;
}
} else {
feedback.textContent = '再试一次!';
feedback.className = 'text-danger';
leftCard.classList.remove('border-green-200', 'border-success');
rightCard.classList.remove('border-orange-200', 'border-success');
leftCard.classList.add('border-danger');
rightCard.classList.add('border-danger');
speak("答错了,再试一次!");
}
setTimeout(generateNumbers, 1500);
}
function levelUp() {
gameState.level++;
document.getElementById('level').textContent = gameState.level;
document.getElementById('new-level').textContent = gameState.level;
if (gameState.level === 2) gameState.maxNum = 7;
if (gameState.level === 3) gameState.maxNum = 10;
document.getElementById('level-up').classList.remove('hidden');
speak(`恭喜晋级!你已晋级到第${gameState.level}关!`);
}
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>

View File

@@ -0,0 +1,522 @@
<!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>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 20px;
background-color: #f0f0f0;
}
.game-container {
max-width: 600px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.question {
font-size: 24px;
margin: 20px 0;
color: #333;
}
.options {
display: flex;
justify-content: center;
gap: 20px;
margin: 30px 0;
}
.option-btn {
padding: 15px 30px;
font-size: 18px;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #007bff;
color: white;
transition: background-color 0.3s;
}
.option-btn:hover {
background-color: #0056b3;
}
.option-btn.correct {
background-color: #28a745;
}
.option-btn.incorrect {
background-color: #dc3545;
}
.result {
font-size: 20px;
margin: 20px 0;
padding: 15px;
border-radius: 5px;
}
.result.correct {
background-color: #d4edda;
color: #155724;
}
.result.incorrect {
background-color: #f8d7da;
color: #721c24;
}
.score {
font-size: 18px;
margin: 20px 0;
color: #666;
}
.restart-btn {
padding: 10px 20px;
font-size: 16px;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #6c757d;
color: white;
margin-top: 20px;
}
.restart-btn:hover {
background-color: #545b62;
}
/* 体感交互视频样式 */
.body-sensation-container {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 20px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
z-index: 1000;
max-width: 600px;
}
.body-video-feed {
position: relative;
width: 500px;
height: 350px;
border-radius: 10px;
overflow: hidden;
margin-bottom: 15px;
}
.body-video-feed img {
width: 100%;
height: 100%;
object-fit: cover;
}
.body-status-overlay {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 15px;
border-radius: 8px;
font-size: 14px;
line-height: 1.3;
}
.body-instruction {
text-align: center;
font-size: 18px;
color: #333;
font-weight: 500;
padding: 8px;
}
/* 体感交互容器样式用于directBodySensation.js */
.box-body {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 20px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
z-index: 2000;
max-width: 500px;
text-align: center;
}
.box-body img {
max-width: 100%;
height: auto;
border-radius: 10px;
margin: 10px 0;
}
.box-body div {
margin: 10px 0;
padding: 5px;
}
</style>
</head>
<body>
<div class="game-container">
<h1>数学小测验</h1>
<div class="question" id="question">2 + 3 = ?</div>
<div class="options" id="options">
<button class="option-btn" onclick="selectOption(4)">4</button>
<button class="option-btn" onclick="selectOption(5)">5</button>
<button class="option-btn" onclick="selectOption(6)">6</button>
</div>
<div class="result" id="result" style="display: none"></div>
<div class="score" id="score">得分: 0</div>
<button class="restart-btn" onclick="restartGame()" style="display: none">
重新开始
</button>
</div>
<!-- 体感交互视频容器 -->
<div
class="body-sensation-container"
id="bodySensationContainer"
style="display: none"
>
<div class="body-video-feed">
<img id="bodyVideoFeed" src="" alt="体感检测视频" />
<div class="body-status-overlay">
<div id="bodyConnectionStatus">未连接到服务器</div>
<div id="bodyHandStatus">等待检测...</div>
</div>
</div>
<div class="body-instruction" id="bodyInstruction">
请举起左手或右手选择答案
</div>
</div>
<!-- 体感交互容器用于directBodySensation.js -->
<div class="box-body" style="display: none">
<div id="bodyConnectionStatus">未连接到服务器</div>
<img id="bodyVideoFeed" src="" alt="体感检测视频" />
<div id="bodyHandStatus">等待检测...</div>
</div>
<!-- 引入后端集成脚本 -->
<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>
<script src="../../js/virtualTeacher.js"></script>
<!-- 引入体感交互脚本 -->
<script src="../../js/directBodySensation.js"></script>
<script>
let currentQuestion = 0;
let score = 0;
let gameStarted = false;
let gameId = 1; // 示例游戏ID实际应该从数据库获取
const questions = [
{ question: "2 + 3 = ?", options: [4, 5, 6], correct: 5 },
{ question: "7 - 2 = ?", options: [4, 5, 6], correct: 5 },
{ question: "3 × 2 = ?", options: [5, 6, 7], correct: 6 },
{ question: "8 ÷ 2 = ?", options: [3, 4, 5], correct: 4 },
{ question: "1 + 1 = ?", options: [1, 2, 3], correct: 2 },
];
// 初始化游戏
function initGame() {
// 检查用户是否已登录
if (!window.userManager.isUserLoggedIn()) {
alert("请先登录后再开始游戏!");
return;
}
// 重置虚拟老师统计
if (window.virtualTeacher) {
window.virtualTeacher.resetStats();
window.virtualTeacher.gameStart("示例游戏");
}
// 开始游戏跟踪
if (window.gameTracker) {
window.gameTracker.startGame(gameId, {
gameType: "math_quiz",
totalQuestions: questions.length,
});
gameStarted = true;
}
currentQuestion = 0;
score = 0;
showQuestion();
}
// 显示问题
function showQuestion() {
if (currentQuestion >= questions.length) {
endGame();
return;
}
const q = questions[currentQuestion];
document.getElementById("question").textContent = q.question;
// 虚拟老师朗读题目
if (window.virtualTeacher) {
const questionText = `${currentQuestion + 1}题:${
q.question
},选项有:${q.options.join("、")}`;
window.virtualTeacher.readQuestion(questionText);
}
const optionsDiv = document.getElementById("options");
optionsDiv.innerHTML = "";
q.options.forEach((option) => {
const btn = document.createElement("button");
btn.className = "option-btn";
btn.textContent = option;
btn.onclick = () => selectOption(option);
optionsDiv.appendChild(btn);
});
// 显示体感交互视频
showBodyInteraction();
// 更新体感交互提示文本
if (q.options.length >= 2) {
updateBodyInstruction(
`请举起左手选择${q.options[0]}或举起右手选择${q.options[1]}`
);
} else if (q.options.length === 1) {
updateBodyInstruction(`请举起任意一只手选择:${q.options[0]}`);
} else {
updateBodyInstruction("请举起左手或右手选择答案");
}
document.getElementById("result").style.display = "none";
document.getElementById("restart-btn").style.display = "none";
}
// 体感交互控制函数
function showBodyInteraction() {
const bodySensationContainer = document.getElementById(
"bodySensationContainer"
);
if (bodySensationContainer) {
bodySensationContainer.style.display = "block";
}
// 启动体感交互系统
if (typeof showBody === "function") {
showBody();
}
}
function hideBodyInteraction() {
const bodySensationContainer = document.getElementById(
"bodySensationContainer"
);
if (bodySensationContainer) {
bodySensationContainer.style.display = "none";
}
}
function updateBodyInstruction(text) {
const bodyInstruction = document.getElementById("bodyInstruction");
if (bodyInstruction) {
bodyInstruction.textContent = text;
}
}
// 选择答案
function selectOption(selected) {
if (!gameStarted) return;
// 隐藏体感交互按钮
hideBodyInteraction();
// 记录游戏尝试
if (window.gameTracker) {
window.gameTracker.recordAttempt();
}
const q = questions[currentQuestion];
const isCorrect = selected === q.correct;
// 虚拟老师反馈
if (window.virtualTeacher) {
// 立即停止当前语音
window.virtualTeacher.stopAllSpeech();
// 延迟一点再播放反馈语音
setTimeout(() => {
if (isCorrect) {
window.virtualTeacher.recordCorrect();
} else {
window.virtualTeacher.recordIncorrect();
}
}, 300);
}
// 详细数据打印
console.log("🎯 示例游戏 - 用户选择记录");
console.log("📊 问题信息:", {
问题编号: currentQuestion + 1,
问题内容: q.question,
选项: q.options,
正确答案: q.correct,
用户选择: selected,
是否正确: isCorrect ? "✅ 正确" : "❌ 错误",
});
console.log("📈 游戏进度:", {
当前得分: score,
当前问题: currentQuestion + 1,
总问题数: questions.length,
完成进度: `${(
((currentQuestion + 1) / questions.length) *
100
).toFixed(1)}%`,
});
console.log("⏰ 时间信息:", {
选择时间: new Date().toLocaleString("zh-CN"),
游戏时长: window.gameTracker
? window.gameTracker.getCurrentPlayTime() + "秒"
: "未知",
});
// 显示结果
const resultDiv = document.getElementById("result");
resultDiv.style.display = "block";
if (isCorrect) {
score += 10;
resultDiv.textContent = "正确!";
resultDiv.className = "result correct";
// 记录正确答案
if (window.gameTracker) {
window.gameTracker.recordCorrect(10, {
question: q.question,
selected: selected,
correct: q.correct,
questionNumber: currentQuestion + 1,
totalQuestions: questions.length,
options: q.options,
});
}
} else {
resultDiv.textContent = `错误!正确答案是 ${q.correct}`;
resultDiv.className = "result incorrect";
// 记录错误答案
if (window.gameTracker) {
window.gameTracker.recordIncorrect(0, {
question: q.question,
selected: selected,
correct: q.correct,
questionNumber: currentQuestion + 1,
totalQuestions: questions.length,
options: q.options,
});
}
}
// 更新得分显示
document.getElementById("score").textContent = `得分: ${score}`;
// 禁用选项按钮
const options = document.querySelectorAll(".option-btn");
options.forEach((btn) => {
btn.disabled = true;
if (parseInt(btn.textContent) === q.correct) {
btn.classList.add("correct");
} else if (parseInt(btn.textContent) === selected && !isCorrect) {
btn.classList.add("incorrect");
}
});
// 延迟显示下一题
setTimeout(() => {
currentQuestion++;
showQuestion();
}, 2000);
}
// 结束游戏
function endGame() {
gameStarted = false;
// 虚拟老师游戏结束反馈
if (window.virtualTeacher) {
// 立即停止当前语音
window.virtualTeacher.stopAllSpeech();
// 延迟一点再播放游戏结束语音
setTimeout(() => {
window.virtualTeacher.gameEnd();
}, 500);
}
// 记录游戏结果
if (window.gameTracker) {
const finalScore = score;
const gameData = {
totalQuestions: questions.length,
correctAnswers: Math.floor(score / 10),
finalScore: finalScore,
};
if (finalScore >= 30) {
window.gameTracker.recordWin(finalScore, gameData);
} else {
window.gameTracker.recordLose(finalScore, gameData);
}
}
// 显示最终结果
document.getElementById("question").textContent = "游戏结束!";
document.getElementById("options").innerHTML = "";
document.getElementById("result").style.display = "block";
document.getElementById("result").textContent = `最终得分: ${score}`;
document.getElementById("result").className = "result correct";
document.getElementById("restart-btn").style.display = "inline-block";
}
// 重新开始游戏
function restartGame() {
initGame();
}
// 页面加载完成后初始化
document.addEventListener("DOMContentLoaded", function () {
// 初始化虚拟老师
if (window.virtualTeacher) {
window.virtualTeacher
.init()
.then(() => {
console.log("🦉 虚拟老师初始化成功");
// 延迟播放游戏介绍,避免与访问跟踪语音冲突
setTimeout(() => {
const gameIntro =
"欢迎来到示例游戏!这是一个简单的选择题游戏,我会为你朗读题目和选项。准备好了吗?";
window.virtualTeacher.readGameIntroduction(gameIntro);
}, 1000);
})
.catch((error) => {
console.error("❌ 虚拟老师初始化失败:", error);
});
}
// 初始化后端集成
Promise.all([window.userManager.init(), window.dataManager.init()])
.then(() => {
console.log("后端集成初始化完成");
// 自动开始游戏
initGame();
})
.catch((error) => {
console.error("后端集成初始化失败:", error);
// 即使后端初始化失败,也可以开始游戏
initGame();
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,507 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>美味餐桌4以内加法</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>
/* 基础样式 */
:root {
--primary: #FF9AA2;
/* 粉色 */
--secondary: #FFB7B2;
/* 浅粉色 */
--accent: #FFDAC1;
/* 米色 */
--food: #E2F0CB;
/* 浅绿色 */
--text: #5E5346;
/* 棕色 */
--correct: #B5EAD7;
/* 浅绿色 */
--wrong: #FF9AA2;
/* 粉色 */
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Comic Sans MS', 'Marker Felt', '微软雅黑', sans-serif;
background-color: var(--accent);
color: var(--text);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: var(--primary);
margin-bottom: 20px;
text-shadow: 2px 2px 0px rgba(0, 0, 0, 0.1);
font-size: 2.2rem;
}
.container {
width: 100%;
max-width: 800px;
background-color: white;
border-radius: 20px;
padding: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
text-align: center;
}
/* 餐桌区域 */
.table-area {
background-color: #F0E6DD;
border: 12px solid #D4A76A;
border-radius: 50%;
width: 100%;
height: 250px;
margin-bottom: 30px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
}
.table-area::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle at center, transparent 60%, rgba(0, 0, 0, 0.1) 100%);
}
.table-items {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
padding: 20px;
width: 100%;
height: 100%;
align-items: center;
}
/* 美食区域 */
.food-area {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
padding: 30px;
background-color: var(--secondary);
border-radius: 15px;
min-height: 150px;
}
/* 美食图片样式 */
.food-item {
width: 80px;
height: 80px;
background-color: var(--food);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: grab;
user-select: none;
transition: all 0.3s ease;
position: relative;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border: 3px solid white;
}
.food-item img {
width: 60px;
height: 60px;
object-fit: contain;
}
.food-item.dragging {
opacity: 0.8;
transform: scale(1.1);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
}
/* 按钮样式 */
.btn {
background-color: var(--primary);
color: white;
border: none;
border-radius: 50px;
padding: 12px 25px;
font-size: 1.2rem;
margin: 10px auto;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
.btn:active {
transform: translateY(1px);
}
/* 提示信息 */
.message {
margin-top: 15px;
padding: 10px 15px;
border-radius: 10px;
font-size: 1.2rem;
text-align: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.message.show {
opacity: 1;
}
.correct {
background-color: var(--correct);
}
.wrong {
background-color: var(--wrong);
}
/* 动画效果 */
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
75% {
transform: translateX(5px);
}
}
.shake {
animation: shake 0.3s ease infinite;
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
.float {
animation: float 2s ease-in-out infinite;
}
/* 庆祝效果 */
.celebration {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.5s ease;
}
.celebration.show {
opacity: 1;
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
/* 响应式设计 */
@media (max-width: 600px) {
h1 {
font-size: 1.8rem;
}
.table-area {
height: 200px;
}
.food-item {
width: 70px;
height: 70px;
}
.food-item img {
width: 50px;
height: 50px;
}
}
</style>
</head>
<body>
<h1>美味餐桌</h1>
<div class="container">
<div class="table-area" id="tableArea">
<div class="table-items" id="tableItems"></div>
</div>
<div class="food-area" id="foodArea"></div>
<button class="btn" id="submitBtn">提交</button>
<div class="message correct show" id="message">请拖动下方美食放置到餐桌上,让餐桌上有四个美食。</div>
</div>
<div class="celebration" id="celebration">
</div>
<script>
// 美食图片数组
const foodImages = [
'🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🍈', '🍒', '🍑', '🥭', '🍍', '🥥', '🥝', '🍅', '🥑', '🥦', '🥕'
];
// DOM元素
const tableArea = document.getElementById('tableArea');
const tableItems = document.getElementById('tableItems');
const foodArea = document.getElementById('foodArea');
const submitBtn = document.getElementById('submitBtn');
const message = document.getElementById('message');
const celebration = document.getElementById('celebration');
// 游戏状态
let initialFoodCount = 0;
let draggedItems = [];
// 初始化游戏
function initGame() {
// 清空餐桌和美食区
tableItems.innerHTML = '';
foodArea.innerHTML = '';
// message.classList.remove('show');
// 随机生成1-3个初始美食
initialFoodCount = Math.floor(Math.random() * 3) + 1;
// 在餐桌上放置初始美食
for (let i = 0; i < initialFoodCount; i++) {
const randomFood = getRandomFood();
const foodItem = createFoodItem(randomFood, false);
tableItems.appendChild(foodItem);
}
// 在美食区放置4个随机美食
for (let i = 0; i < 4; i++) {
const randomFood = getRandomFood();
const foodItem = createFoodItem(randomFood, true);
foodArea.appendChild(foodItem);
}
// 重置拖动记录
draggedItems = [];
}
// 获取随机美食
function getRandomFood() {
const randomIndex = Math.floor(Math.random() * foodImages.length);
return foodImages[randomIndex];
}
// 创建美食元素
function createFoodItem(food, isDraggable) {
const foodItem = document.createElement('div');
foodItem.className = 'food-item float';
foodItem.innerHTML = `<span style="font-size: 2.5rem">${food}</span>`;
if (isDraggable) {
foodItem.draggable = true;
// 拖动开始
foodItem.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', food);
foodItem.classList.add('dragging');
setTimeout(() => {
foodItem.style.display = 'none';
}, 0);
});
// 拖动结束
foodItem.addEventListener('dragend', () => {
foodItem.classList.remove('dragging');
foodItem.style.display = 'flex';
});
}
return foodItem;
}
// 优化后的拖动放置逻辑
tableArea.addEventListener('dragover', (e) => {
e.preventDefault();
// 添加视觉效果提示可以放置
tableArea.style.boxShadow = 'inset 0 0 20px rgba(255, 154, 162, 0.5)';
});
tableArea.addEventListener('dragleave', () => {
// 移除视觉效果
tableArea.style.boxShadow = 'none';
});
tableArea.addEventListener('drop', (e) => {
e.preventDefault();
// 移除视觉效果
tableArea.style.boxShadow = 'none';
const food = e.dataTransfer.getData('text/plain');
// 创建美食并添加到餐桌
const foodItem = createFoodItem(food, false);
tableItems.appendChild(foodItem);
// 记录拖动的美食
draggedItems.push(food);
});
// 提交答案
submitBtn.addEventListener('click', () => {
const totalFood = initialFoodCount + draggedItems.length;
// 详细数据打印
console.log('🎯 美味餐桌游戏 - 提交答案记录');
console.log('📊 答案信息:', {
初始美食数量: initialFoodCount,
拖拽美食数量: draggedItems.length,
总美食数量: totalFood,
正确答案: 4,
是否正确: totalFood === 4 ? '✅ 正确' : '❌ 错误',
提交时间: new Date().toLocaleString('zh-CN')
});
console.log('📈 游戏进度:', {
拖拽的美食: draggedItems,
操作次数: draggedItems.length
});
// 清除之前的提示和动画
message.classList.remove('show');
document.querySelectorAll('.shake').forEach(el => {
el.classList.remove('shake');
});
if (totalFood === 4) {
// 答案正确
message.textContent = '太棒了正好4个美食';
message.className = 'message correct show';
celebrate();
} else if (totalFood < 4) {
// 美食不足
const needed = 4 - totalFood;
message.textContent = `还有我们呀!还需要${needed}个美食~`;
message.className = 'message wrong show';
// 让美食区的美食抖动
const foodItems = foodArea.querySelectorAll('.food-item');
for (let i = 0; i < needed && i < foodItems.length; i++) {
foodItems[i].classList.add('shake');
}
} else {
// 美食过多
const extra = totalFood - 4;
message.textContent = '吃不下这么多呢!太多了~';
message.className = 'message wrong show';
// 让餐桌上多余的美食抖动
const tableFoods = tableItems.querySelectorAll('.food-item');
for (let i = tableFoods.length - 1; i >= tableFoods.length - extra; i--) {
tableFoods[i].classList.add('shake');
}
}
// 3秒后重新开始游戏
setTimeout(initGame, 3000);
});
// 庆祝效果
function celebrate() {
celebration.innerHTML = '';
celebration.classList.add('show');
// 创建彩色纸屑
for (let i = 0; i < 50; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = `${Math.random() * 100}vw`;
confetti.style.backgroundColor = getRandomColor();
confetti.style.animation = `confetti-fall ${Math.random() * 2 + 2}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
celebration.appendChild(confetti);
}
// 3秒后隐藏庆祝效果
setTimeout(() => {
celebration.classList.remove('show');
}, 3000);
}
// 获取随机颜色
function getRandomColor() {
const colors = ['#FF9AA2', '#FFB7B2', '#FFDAC1', '#E2F0CB', '#B5EAD7', '#C7CEEA'];
return colors[Math.floor(Math.random() * colors.length)];
}
// 初始化游戏
initGame();
</script>
</body>
</html>

View File

@@ -0,0 +1,422 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>美味餐桌4以内加法</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>
:root {
--primary: #FF9AA2;
--secondary: #FFB7B2;
--accent: #FFDAC1;
--food: #E2F0CB;
--text: #5E5346;
--correct: #B5EAD7;
--wrong: #FF9AA2;
--button: #70A1FF;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Comic Sans MS', 'Marker Felt', '微软雅黑', sans-serif;
background-color: var(--accent);
color: var(--text);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: var(--primary);
margin-bottom: 20px;
text-shadow: 2px 2px 0px rgba(0, 0, 0, 0.1);
font-size: 2.2rem;
}
.container {
width: 100%;
max-width: 800px;
background-color: white;
border-radius: 20px;
padding: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
/* 餐桌区域 */
.table-area {
background-color: #F0E6DD;
border: 12px solid #D4A76A;
border-radius: 50%;
width: 100%;
height: 250px;
margin-bottom: 30px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
}
.table-area::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle at center, transparent 60%, rgba(0, 0, 0, 0.1) 100%);
}
.table-items {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
padding: 20px;
width: 100%;
height: 100%;
align-items: center;
}
/* 食物图片样式 */
.food-item {
width: 80px;
height: 80px;
background-color: var(--food);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s ease;
position: relative;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border: 3px solid white;
}
.food-item img {
width: 60px;
height: 60px;
object-fit: contain;
}
/* 按钮区域 */
.button-area {
display: flex;
justify-content: center;
gap: 20px;
padding: 15px;
background-color: var(--secondary);
border-radius: 15px;
}
.number-btn {
width: 70px;
height: 70px;
border-radius: 50%;
background-color: var(--button);
color: white;
font-size: 2rem;
font-weight: bold;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.number-btn:hover {
transform: translateY(-5px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}
.number-btn:active {
transform: translateY(0);
}
/* 提示信息 */
.message {
margin-top: 15px;
padding: 10px 15px;
border-radius: 10px;
font-size: 1.2rem;
text-align: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.message.show {
opacity: 1;
}
.correct {
background-color: var(--correct);
}
.wrong {
background-color: var(--wrong);
}
/* 动画效果 */
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
75% {
transform: translateX(5px);
}
}
.shake {
animation: shake 0.3s ease infinite;
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
.float {
animation: float 2s ease-in-out infinite;
}
/* 庆祝效果 */
.celebration {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.5s ease;
}
.celebration.show {
opacity: 1;
}
.confetti {
position: absolute;
width: 15px;
height: 15px;
background-color: var(--primary);
opacity: 0;
}
@keyframes confetti-fall {
0% {
transform: translateY(-100vh) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
@media (max-width: 600px) {
h1 {
font-size: 1.8rem;
}
.table-area {
height: 200px;
}
.food-item {
width: 60px;
height: 60px;
}
.food-item img {
width: 50px;
height: 50px;
}
.number-btn {
width: 50px;
height: 50px;
font-size: 1.5rem;
}
}
</style>
</head>
<body>
<h1>美味餐桌</h1>
<div class="container">
<div class="table-area">
<div class="table-items" id="tableItems"></div>
</div>
<div class="button-area">
<button class="number-btn" id="btn1">1</button>
<button class="number-btn" id="btn2">2</button>
<button class="number-btn" id="btn3">3</button>
<button class="number-btn" id="btn4">4</button>
</div>
<div class="message" id="message"></div>
</div>
<div class="celebration" id="celebration"></div>
<script>
// 食物图片数组
const foodImages = [
'🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🍈', '🍒', '🍑', '🥭', '🍍', '🥥', '🥝', '🍅', '🥑', '🥦', '🥕'
];
// DOM元素
const tableItems = document.getElementById('tableItems');
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
const btn3 = document.getElementById('btn3');
const btn4 = document.getElementById('btn4');
const message = document.getElementById('message');
const celebration = document.getElementById('celebration');
// 游戏状态
let currentFoodCount = 0;
// 初始化游戏
function initGame() {
// 清空餐桌
tableItems.innerHTML = '';
message.classList.remove('show');
// 随机生成1-4个食物
currentFoodCount = Math.floor(Math.random() * 4) + 1;
// 在餐桌上放置食物
for (let i = 0; i < currentFoodCount; i++) {
const randomFood = getRandomFood();
const foodItem = createFoodItem(randomFood);
tableItems.appendChild(foodItem);
}
}
// 获取随机食物
function getRandomFood() {
const randomIndex = Math.floor(Math.random() * foodImages.length);
return foodImages[randomIndex];
}
// 创建食物元素
function createFoodItem(food) {
const foodItem = document.createElement('div');
foodItem.className = 'food-item float';
foodItem.innerHTML = `<span style="font-size: 2.5rem">${food}</span>`;
return foodItem;
}
// 检查答案
function checkAnswer(selectedNumber) {
// 清除之前的提示
message.classList.remove('show');
if (selectedNumber === currentFoodCount) {
// 答案正确
message.textContent = '太棒了!答对了!';
message.className = 'message correct show';
celebrate();
// 1秒后生成新题目
setTimeout(initGame, 1000);
} else {
// 答案错误
message.textContent = `不对哦!正确答案是 ${currentFoodCount} 个食物~`;
message.className = 'message wrong show';
// 让餐桌上的食物抖动
const foodItems = tableItems.querySelectorAll('.food-item');
foodItems.forEach(item => {
item.classList.add('shake');
});
// 3秒后停止抖动
setTimeout(() => {
foodItems.forEach(item => {
item.classList.remove('shake');
});
}, 3000);
}
}
// 按钮点击事件
btn1.addEventListener('click', () => checkAnswer(1));
btn2.addEventListener('click', () => checkAnswer(2));
btn3.addEventListener('click', () => checkAnswer(3));
btn4.addEventListener('click', () => checkAnswer(4));
// 庆祝效果
function celebrate() {
celebration.innerHTML = '';
celebration.classList.add('show');
// 创建彩色纸屑
for (let i = 0; i < 50; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.left = `${Math.random() * 100}vw`;
confetti.style.backgroundColor = getRandomColor();
confetti.style.animation = `confetti-fall ${Math.random() * 2 + 2}s linear forwards`;
confetti.style.animationDelay = `${Math.random() * 0.5}s`;
celebration.appendChild(confetti);
}
// 3秒后隐藏庆祝效果
setTimeout(() => {
celebration.classList.remove('show');
}, 3000);
}
// 获取随机颜色
function getRandomColor() {
const colors = ['#FF9AA2', '#FFB7B2', '#FFDAC1', '#E2F0CB', '#B5EAD7', '#C7CEEA'];
return colors[Math.floor(Math.random() * colors.length)];
}
// 初始化游戏
initGame();
</script>
</body>
</html>

View File

@@ -0,0 +1,836 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数学小精灵 - 培智学校生活数学游戏</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- 引入后端集成脚本 -->
<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;
font-family: 'Comic Sans MS', '华文圆体', cursive;
}
body {
background: linear-gradient(135deg, #6ecbf5, #a17fe0);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
padding: 20px;
}
.game-container {
width: 95%;
max-width: 900px;
background: rgba(255, 255, 255, 0.92);
border-radius: 30px;
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
overflow: hidden;
position: relative;
min-height: 85vh;
}
.game-header {
background: linear-gradient(to right, #ff9a9e, #fad0c4);
padding: 20px 30px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
.logo {
display: flex;
align-items: center;
}
.logo img {
width: 60px;
height: 60px;
margin-right: 15px;
}
.logo-text {
font-size: 28px;
font-weight: bold;
color: #d43f8d;
text-shadow: 2px 2px 0 #ffd7e9;
}
.level-info {
background: rgba(255, 255, 255, 0.8);
padding: 10px 25px;
border-radius: 20px;
font-size: 20px;
font-weight: bold;
color: #ff6b6b;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
}
/* 主内容区 */
.game-content {
padding: 30px;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
min-height: 60vh;
}
/* 欢迎屏幕 */
.welcome-screen {
text-align: center;
padding: 40px 0;
animation: bounceIn 1s;
}
.welcome-title {
font-size: 48px;
color: #ff7b54;
margin-bottom: 30px;
text-shadow: 2px 2px 0 #ffe1c6;
}
.welcome-subtitle {
font-size: 28px;
color: #5c7cfa;
margin-bottom: 40px;
}
.character {
width: 200px;
height: 200px;
background: #ffb6c1;
border-radius: 50%;
margin: 20px auto 40px;
position: relative;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.character::before {
content: "😊";
font-size: 100px;
}
.start-button {
background: linear-gradient(to right, #ff9a9e, #fad0c4);
color: white;
font-size: 28px;
padding: 15px 50px;
border: none;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
transition: all 0.3s;
font-weight: bold;
}
.start-button:hover {
transform: scale(1.05);
box-shadow: 0 12px 20px rgba(0, 0, 0, 0.15);
}
/* 关卡选择 */
.level-selection {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 25px;
margin: 30px 0 50px;
width: 100%;
max-width: 800px;
}
.level-card {
background: white;
border-radius: 20px;
padding: 25px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.3s;
border: 4px solid transparent;
position: relative;
overflow: hidden;
}
.level-card:hover {
transform: translateY(-10px);
border-color: #ff9a9e;
}
.level-icon {
width: 100px;
height: 100px;
background: #ffecb5;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
font-size: 50px;
color: #ff9a9e;
}
.level-name {
font-size: 22px;
color: #5c7cfa;
font-weight: bold;
margin-bottom: 10px;
}
.level-desc {
font-size: 18px;
color: #666;
text-align: center;
}
/* 游戏区 */
.game-area {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.game-question {
font-size: 32px;
color: #2d6cdf;
margin-bottom: 30px;
text-align: center;
background: #e6f4ff;
padding: 15px 30px;
border-radius: 15px;
border: 3px dashed #a0c4ff;
width: 100%;
max-width: 600px;
}
.game-options {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 25px;
margin: 30px 0;
width: 100%;
max-width: 800px;
}
.game-option {
width: 120px;
height: 120px;
background: #ffde7d;
border-radius: 20px;
display: flex;
justify-content: center;
align-items: center;
font-size: 60px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
position: relative;
}
.game-option:hover {
transform: scale(1.1);
}
/* 视觉提示区 */
.visual-prompt {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
margin: 30px 0;
padding: 20px;
background: #f6f7f9;
border-radius: 20px;
border: 3px solid #e0e0e0;
width: 100%;
max-width: 600px;
}
.visual-item {
width: 70px;
height: 70px;
background: #a0c4ff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
}
/* 反馈与导航 */
.feedback-area {
position: absolute;
bottom: 30px;
left: 0;
right: 0;
display: flex;
justify-content: center;
}
.feedback-text {
font-size: 36px;
font-weight: bold;
padding: 20px 40px;
border-radius: 20px;
animation: pop 0.5s;
}
.correct {
background: #d4edda;
color: #155724;
border: 3px solid #c3e6cb;
}
.incorrect {
background: #f8d7da;
color: #721c24;
border: 3px solid #f5c6cb;
}
.nav-buttons {
display: flex;
gap: 20px;
margin-top: 30px;
}
.nav-button {
background: #78c4d4;
color: white;
border: none;
border-radius: 20px;
padding: 15px 30px;
font-size: 22px;
cursor: pointer;
display: flex;
align-items: center;
gap: 10px;
transition: all 0.3s;
}
.nav-button:hover {
background: #5db8cb;
transform: scale(1.05);
}
/* 动画 */
@keyframes bounceIn {
from {
opacity: 0;
transform: scale(0.5);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes pop {
0% { transform: scale(0.8); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-15px); }
100% { transform: translateY(0px); }
}
/* 进度条 */
.progress-bar {
height: 20px;
background: #e0e0e0;
border-radius: 10px;
overflow: hidden;
width: 90%;
max-width: 700px;
margin: 20px 0;
}
.progress {
height: 100%;
background: linear-gradient(to right, #ff9a9e, #fad0c4);
border-radius: 10px;
width: 0%;
transition: width 0.5s ease-in-out;
}
/* 响应式设计 */
@media (max-width: 768px) {
.level-selection {
grid-template-columns: 1fr;
}
.game-options {
flex-wrap: wrap;
}
.game-option {
width: 100px;
height: 100px;
}
.welcome-title {
font-size: 36px;
}
}
.floating-element {
position: absolute;
animation: float 4s infinite ease-in-out;
}
.element-1 {
top: 50px;
left: 50px;
font-size: 50px;
color: #ff9a9e;
}
.element-2 {
bottom: 50px;
right: 50px;
font-size: 50px;
color: #5c7cfa;
}
</style>
</head>
<body>
<div class="game-container">
<div class="game-header">
<div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDAgMjAwIj48Y2lyY2xlIGN4PSIxMDAiIGN5PSIxMDAiIHI9Ijk1IiBmaWxsPSIjRkZCQzREIi8+PHBhdGggZD0iTTcwLDEyMCBRMTAwLDE0MCAxMzAsMTIwIiBzdHJva2U9IiNGRjY4QjAiIHN0cm9rZS13aWR0aD0iOCIvPjxjaXJjbGUgY3g9IjgwIiBjeT0iODAiIHI9IjEwIiBmaWxsPSIjMzMzIi8+PGNpcmNsZSBjeD0iMTIwIiBjeT0iODAiIHI9IjEwIiBmaWxsPSIjMzMzIi8+PC9zdmc+" alt="数学小精灵">
<div class="logo-text">数学小精灵</div>
</div>
<div class="level-info"><span id="currentLevel">1</span></div>
</div>
<div class="game-content">
<!-- 欢迎界面 -->
<div class="welcome-screen" id="welcomeScreen">
<h1 class="welcome-title">生活数学小游戏</h1>
<h2 class="welcome-subtitle">一起来探索数字的奥秘吧!</h2>
<div class="character"></div>
<button class="start-button" id="startButton">
<i class="fas fa-play"></i> 开始游戏
</button>
</div>
<!-- 关卡选择 -->
<div id="levelSelection" class="level-selection" style="display:none;">
<div class="level-card" data-level="1">
<div class="level-icon">🔢</div>
<div class="level-name">认识数字</div>
<div class="level-desc">匹配数字和对应数量的物品</div>
</div>
<div class="level-card" data-level="2">
<div class="level-icon"></div>
<div class="level-name">数一数</div>
<div class="level-desc">点数物品并选择数字</div>
</div>
<div class="level-card" data-level="3">
<div class="level-icon"></div>
<div class="level-name">简单加减</div>
<div class="level-desc">5以内的加法</div>
</div>
</div>
<!-- 游戏区域 -->
<div id="gameArea" class="game-area" style="display:none;">
<div class="progress-bar">
<div class="progress" id="progressBar"></div>
</div>
<div class="game-question" id="question"></div>
<div class="visual-prompt" id="visualPrompt"></div>
<div class="game-options" id="optionsContainer"></div>
<div class="feedback-area">
<div id="feedback" class="feedback-text" style="display:none;"></div>
</div>
<div class="nav-buttons">
<button class="nav-button" id="replayButton" style="display:none;">
<i class="fas fa-redo"></i> 再听一次
</button>
<button class="nav-button" id="nextButton" style="display:none;">
下一题 <i class="fas fa-arrow-right"></i>
</button>
</div>
</div>
</div>
<!-- 浮动元素增加趣味性 -->
<div class="floating-element element-1">🌼</div>
<div class="floating-element element-2">🌈</div>
</div>
<script>
// 游戏状态管理
const gameState = {
currentLevel: 1,
currentQuestion: 0,
totalQuestions: 5,
questionsCorrect: 0
};
// 关卡数据
const levels = {
1: {
title: "认识数字",
questions: [
{
prompt: "找出数字3",
visual: [],
options: [1, 3, 5, 2],
correctIndex: 1
},
{
prompt: "找出数字5",
visual: [],
options: [2, 4, 5, 1],
correctIndex: 2
},
{
prompt: "找出数字2",
visual: [],
options: [3, 4, 2, 5],
correctIndex: 2
},
{
prompt: "找出数字4",
visual: [],
options: [1, 3, 4, 2],
correctIndex: 2
},
{
prompt: "找出数字1",
visual: [],
options: [4, 1, 5, 3],
correctIndex: 1
}
]
},
2: {
title: "数一数",
questions: [
{
prompt: "数一数有多少个苹果",
visual: ["🍎", "🍎", "🍎"],
options: [2, 3, 4, 5],
correctIndex: 1
},
{
prompt: "数一数有多少辆汽车",
visual: ["🚗", "🚗"],
options: [1, 2, 3, 4],
correctIndex: 1
},
{
prompt: "数一数有多少个气球",
visual: ["🎈", "🎈", "🎈", "🎈", "🎈"],
options: [3, 4, 5, 6],
correctIndex: 2
},
{
prompt: "数一数有多少只小狗",
visual: ["🐶", "🐶", "🐶"],
options: [1, 2, 3, 4],
correctIndex: 2
},
{
prompt: "数一数有多少朵花",
visual: ["🌼", "🌼", "🌼", "🌼"],
options: [3, 4, 5, 6],
correctIndex: 1
}
]
},
3: {
title: "简单加减",
questions: [
{
prompt: "1 加 2 等于多少?",
visual: ["1", "+", "2", "="],
options: [2, 3, 4, 5],
correctIndex: 1
},
{
prompt: "3 加 1 等于多少?",
visual: ["3", "+", "1", "="],
options: [2, 3, 4, 5],
correctIndex: 2
},
{
prompt: "2 加 2 等于多少?",
visual: ["2", "+", "2", "="],
options: [1, 2, 3, 4],
correctIndex: 3
},
{
prompt: "4 加 1 等于多少?",
visual: ["4", "+", "1", "="],
options: [3, 4, 5, 6],
correctIndex: 2
},
{
prompt: "0 加 3 等于多少?",
visual: ["0", "+", "3", "="],
options: [0, 1, 2, 3],
correctIndex: 3
}
]
}
};
// DOM元素
const dom = {
welcomeScreen: document.getElementById('welcomeScreen'),
levelSelection: document.getElementById('levelSelection'),
gameArea: document.getElementById('gameArea'),
question: document.getElementById('question'),
visualPrompt: document.getElementById('visualPrompt'),
optionsContainer: document.getElementById('optionsContainer'),
feedback: document.getElementById('feedback'),
nextButton: document.getElementById('nextButton'),
replayButton: document.getElementById('replayButton'),
progressBar: document.getElementById('progressBar'),
currentLevelElement: document.getElementById('currentLevel')
};
// 初始化游戏
function initGame() {
// 事件监听
document.getElementById('startButton').addEventListener('click', showLevelSelection);
document.querySelectorAll('.level-card').forEach(card => {
card.addEventListener('click', () => {
gameState.currentLevel = parseInt(card.dataset.level);
startGame();
});
});
dom.nextButton.addEventListener('click', nextQuestion);
dom.replayButton.addEventListener('click', playQuestion);
}
// 显示关卡选择界面
function showLevelSelection() {
dom.welcomeScreen.style.display = 'none';
dom.levelSelection.style.display = 'grid';
// 添加动画效果
const cards = document.querySelectorAll('.level-card');
cards.forEach((card, index) => {
setTimeout(() => {
card.style.opacity = 0;
card.style.transform = 'translateY(30px)';
setTimeout(() => {
card.style.transition = 'all 0.5s ease-out';
card.style.opacity = 1;
card.style.transform = 'translateY(0)';
}, 50);
}, index * 200);
});
}
// 开始游戏
function startGame() {
dom.levelSelection.style.display = 'none';
dom.gameArea.style.display = 'flex';
dom.currentLevelElement.textContent = gameState.currentLevel;
gameState.currentQuestion = 0;
gameState.questionsCorrect = 0;
updateProgressBar();
showQuestion();
}
// 显示问题
function showQuestion() {
const level = levels[gameState.currentLevel];
const question = level.questions[gameState.currentQuestion];
// 更新问题文本
dom.question.textContent = question.prompt;
// 更新视觉提示
dom.visualPrompt.innerHTML = '';
if(question.visual.length > 0) {
question.visual.forEach(item => {
const itemElement = document.createElement('div');
itemElement.className = 'visual-item';
itemElement.textContent = item;
dom.visualPrompt.appendChild(itemElement);
});
}
// 创建选项
dom.optionsContainer.innerHTML = '';
question.options.forEach((option, index) => {
const optionElement = document.createElement('div');
optionElement.className = 'game-option';
optionElement.textContent = option;
optionElement.dataset.index = index;
optionElement.addEventListener('click', () => {
checkAnswer(index);
});
dom.optionsContainer.appendChild(optionElement);
});
// 播放问题语音
playQuestion();
// 隐藏按钮
dom.feedback.style.display = 'none';
dom.nextButton.style.display = 'none';
dom.replayButton.style.display = 'none';
}
// 播放问题提示
function playQuestion() {
const level = levels[gameState.currentLevel];
const question = level.questions[gameState.currentQuestion];
// 在实际应用中,这里会播放语音
console.log("播放语音提示:", question.prompt);
// 添加视觉反馈 - 边框闪烁
dom.question.style.animation = 'none';
setTimeout(() => {
dom.question.style.animation = 'pop 0.5s';
}, 10);
}
// 检查答案
function checkAnswer(selectedIndex) {
const level = levels[gameState.currentLevel];
const question = level.questions[gameState.currentQuestion];
const isCorrect = selectedIndex === question.correctIndex;
// 播放音效
playSoundEffect(isCorrect);
if (isCorrect) {
gameState.questionsCorrect++;
// 显示正确反馈
dom.feedback.textContent = "✓ 太棒了!答对了!";
dom.feedback.className = 'feedback-text correct';
// 为正确选项添加效果
const options = document.querySelectorAll('.game-option');
options[selectedIndex].style.background = '#a8e6cf';
options[selectedIndex].style.transform = 'scale(1.2)';
} else {
// 显示错误反馈
dom.feedback.textContent = "✗ 再试一次!";
dom.feedback.className = 'feedback-text incorrect';
// 为错误选项添加效果
const option = document.querySelector(`.game-option[data-index="${selectedIndex}"]`);
option.style.background = '#ff8b94';
// 显示正确选项
const correctOption = document.querySelector(`.game-option[data-index="${question.correctIndex}"]`);
correctOption.style.background = '#a8e6cf';
correctOption.style.border = '3px solid #64c4a4';
}
// 显示反馈和按钮
dom.feedback.style.display = 'block';
dom.nextButton.style.display = 'flex';
dom.replayButton.style.display = 'flex';
// 更新进度条
updateProgressBar();
}
// 下一题
function nextQuestion() {
gameState.currentQuestion++;
if (gameState.currentQuestion < gameState.totalQuestions) {
showQuestion();
} else {
showResults();
}
}
// 更新进度条
function updateProgressBar() {
const progress = (gameState.currentQuestion / gameState.totalQuestions) * 100;
dom.progressBar.style.width = `${progress}%`;
}
// 显示结果
function showResults() {
const accuracy = Math.round((gameState.questionsCorrect / gameState.totalQuestions) * 100);
dom.question.innerHTML = `
<div style="text-align: center;">
<div style="font-size: 42px; color: #ff7b54; margin-bottom: 20px;">游戏完成!</div>
<div style="font-size: 36px; margin-bottom: 30px;">正确率: ${accuracy}%</div>
<div style="font-size: 80px; color: ${accuracy > 70 ? '#4caf50' : '#ff6b6b'};">
${accuracy > 70 ? '🥇' : accuracy > 50 ? '🥈' : '🥉'}
</div>
</div>
`;
dom.visualPrompt.style.display = 'none';
dom.optionsContainer.innerHTML = '';
dom.feedback.style.display = 'none';
dom.nextButton.style.display = 'none';
dom.replayButton.style.display = 'none';
// 添加重新开始按钮
const restartButton = document.createElement('button');
restartButton.className = 'start-button';
restartButton.style.marginTop = '30px';
restartButton.innerHTML = '<i class="fas fa-redo"></i> 再玩一次';
restartButton.addEventListener('click', showLevelSelection);
dom.optionsContainer.appendChild(restartButton);
// 播放结果音效
playSoundEffect(accuracy > 70);
}
// 播放音效
function playSoundEffect(isPositive) {
// 实际项目中会使用真实的音效文件
// 这里使用控制台输出代替
console.log(`播放音效: ${isPositive ? '正确' : '错误'}`);
}
// 初始化游戏
window.onload = initGame;
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff