初始化
701
rg-09112127/html/play/AI数学加法游戏.html
Normal 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>
|
||||
653
rg-09112127/html/play/AI数学比大小游戏.html
Normal 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>
|
||||
609
rg-09112127/html/play/AI生活安全游戏.html
Normal 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>
|
||||
600
rg-09112127/html/play/AI语文拼音游戏.html
Normal 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>
|
||||
BIN
rg-09112127/html/play/MP3/失败.mp3
Normal file
BIN
rg-09112127/html/play/MP3/失败啊哦.mp3
Normal file
BIN
rg-09112127/html/play/MP3/最终失败.mp3
Normal file
BIN
rg-09112127/html/play/MP3/最终胜利.mp3
Normal file
BIN
rg-09112127/html/play/MP3/最终胜利2.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景1.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音1.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音2.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音3.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音4.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音5.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音6.mp3
Normal file
BIN
rg-09112127/html/play/MP3/背景音7.mp3
Normal file
BIN
rg-09112127/html/play/MP3/胜利1.mp3
Normal file
BIN
rg-09112127/html/play/MP3/胜利3.mp3
Normal file
BIN
rg-09112127/html/play/MP3/胜利4.mp3
Normal file
BIN
rg-09112127/html/play/img/.DS_Store
vendored
Normal file
BIN
rg-09112127/html/play/img/1/.DS_Store
vendored
Normal file
BIN
rg-09112127/html/play/img/1/1.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
rg-09112127/html/play/img/1/2.png
Normal file
|
After Width: | Height: | Size: 745 KiB |
BIN
rg-09112127/html/play/img/2/.DS_Store
vendored
Normal file
BIN
rg-09112127/html/play/img/2/1.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
rg-09112127/html/play/img/2/2.png
Normal file
|
After Width: | Height: | Size: 748 KiB |
BIN
rg-09112127/html/play/img/3/.DS_Store
vendored
Normal file
BIN
rg-09112127/html/play/img/3/1.png
Normal file
|
After Width: | Height: | Size: 915 KiB |
BIN
rg-09112127/html/play/img/3/2.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
rg-09112127/html/play/img/4/.DS_Store
vendored
Normal file
BIN
rg-09112127/html/play/img/4/1.png
Normal file
|
After Width: | Height: | Size: 846 KiB |
BIN
rg-09112127/html/play/img/4/2.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
rg-09112127/html/play/img/5/.DS_Store
vendored
Normal file
BIN
rg-09112127/html/play/img/5/1.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
rg-09112127/html/play/img/5/2.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
372
rg-09112127/html/play/数字探险馆.html
Normal 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>
|
||||
|
||||
709
rg-09112127/html/play/比大小.html
Normal 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>
|
||||
293
rg-09112127/html/play/比大小1.html
Normal 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>
|
||||
522
rg-09112127/html/play/示例游戏.html
Normal 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>
|
||||
507
rg-09112127/html/play/美味餐桌01(4以内加法).html
Normal 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>
|
||||
422
rg-09112127/html/play/美味餐桌02(4以内加法).html
Normal 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>
|
||||
836
rg-09112127/html/play/认识数字3.html
Normal 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>
|
||||