702 lines
19 KiB
HTML
702 lines
19 KiB
HTML
|
|
<!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>
|