🎮ArcadeLab

数字掉落 - 小学数学闯关小游戏

by SonicStar40
417 lines14.5 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>数字掉落 - 小学数学闯关小游戏</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;font-family:"微软雅黑",system-ui,sans-serif;}
body{overflow:hidden;background:linear-gradient(160deg,#87CEEB,#c0e8ff);color:#222;height:100vh;width:100vw;}
/* 顶部工具栏 */
.top-bar{
    position:fixed;top:0;left:0;width:100%;height:64px;
    background:rgba(255,255,255,0.85);display:flex;align-items:center;justify-content:space-between;
    padding:0 14px;z-index:999;box-shadow:0 2px 8px #99c8e8;
}
.top-bar button{
    background:#3498db;border:none;color:#fff;padding:8px 10px;border-radius:10px;
    font-size:14px;cursor:pointer;margin:0 3px;transition:0.2s;
}
.top-bar button:hover{background:#2179b9;}
.info-text{font-size:17px;font-weight:bold;color:#1a4c70;}
/* 游戏画布 */
#gameArea{
    width:100vw;height:100vh;position:relative;
    padding-top:64px;
}
/* 掉落数字/算式元素 卡通样式 */
.fall-item{
    position:absolute;font-size:30px;font-weight:bold;
    padding:6px 14px;border-radius:16px;
    background:rgba(52,152,219,0.8);cursor:pointer;
    user-select:none;box-shadow:0 3px 10px #72b8e6;color:#fff;
    border:2px solid #fff;
}
/* 弹窗通用样式 */
.modal{
    position:fixed;top:0;left:0;width:100%;height:100%;
    background:rgba(0,0,0,0.6);display:none;align-items:center;justify-content:center;
    z-index:9999;
}
.modal-box{
    background:#fff;color:#111;padding:28px;max-width:92%;width:540px;
    border-radius:20px;font-size:17px;line-height:1.8;box-shadow:0 0 20px #66a8d8;
}
.modal-box h3{margin-bottom:14px;color:#2369a0;text-align:center;}
.modal-box h2{text-align:center;color:#195788;margin-bottom:16px;}
.modal-box button{
    margin-top:18px;padding:10px 26px;background:#3498db;color:white;
    border:none;border-radius:12px;font-size:16px;cursor:pointer;display:block;margin-left:auto;margin-right:auto;
}
.modal-box button:hover{background:#2179b9;}
/* 底部计分面板 */
.score-panel{
    position:fixed;bottom:22px;left:22px;z-index:998;
    font-size:19px;background:rgba(255,255,255,0.8);padding:12px 20px;border-radius:14px;
    box-shadow:0 2px 10px #a2cbe6;color:#164263;
}
/* 难度升级提示文字 */
.level-tag{position:fixed;top:72px;left:50%;transform:translateX(-50%);font-size:20px;font-weight:bold;z-index:997;color:#c0392b;background:#fff8f8;padding:4px 16px;border-radius:12px;}
/* 最高分显示 */
.high-score{
    position:fixed;bottom:22px;right:22px;z-index:998;
    font-size:17px;background:rgba(255,255,255,0.8);padding:10px 16px;border-radius:12px;color:#b04000;
}
</style>
</head>
<body>
<!-- 顶部控制栏:新增返回主页按钮 -->
<div class="top-bar">
    <div>
        <button id="homeBtn">🏠 返回主页</button>
        <button id="pauseBtn">⏸️ 暂停</button>
        <button id="noteBtn">📒 知识点笔记本</button>
        <button id="musicBtn" disabled style="opacity:0.5;">🔇音乐</button>
    </div>
    <div class="info-text" id="levelTip">请先选择关卡开始游戏</div>
</div>

<div class="level-tag" id="diffTip"></div>
<!-- 游戏主区域 -->
<div id="gameArea"></div>

<!-- 计分面板 -->
<div class="score-panel">
    当前得分:<span id="scoreNum">0</span> / 目标:<span id="targetScore">100</span>
    <br/>失误次数:<span id="wrongNum">0</span>/3
</div>
<!-- 本地最高分 -->
<div class="high-score">🏆 历史最高分:<span id="highScoreText">0</span></div>

<!-- 1.笔记本知识点弹窗 -->
<div class="modal" id="noteModal">
    <div class="modal-box">
        <h3>📖 本关数学知识点</h3>
        <div id="noteContent"></div>
        <button onclick="closeModal('noteModal')">关闭笔记</button>
    </div>
</div>

<!-- 2.难度升级弹窗 -->
<div class="modal" id="diffModal">
    <div class="modal-box" style="text-align:center;">
        <h3 style="color:#c0392b">⚠️ 注意!难度升级</h3>
        <p>接下来会同时掉落数字与加减乘除算式!<br>需要先计算算式结果,再判断是否符合关卡条件</p>
        <button onclick="closeModal('diffModal')">接受挑战</button>
    </div>
</div>

<!-- 3.失误三次重置关卡弹窗 -->
<div class="modal" id="resetModal">
    <div class="modal-box" style="text-align:center;">
        <h3 style="color:#c0392b">失误达到3次!关卡重置</h3>
        <p>别灰心,点击笔记本复习知识点再挑战一次</p>
        <button onclick="resetLevel()">重新开始本关</button>
    </div>
</div>

<!-- 4.通关成功弹窗 -->
<div class="modal" id="winModal">
    <div class="modal-box" style="text-align:center;">
        <h2>🎉 恭喜通关本关!</h2>
        <p>你成功达到目标分数,数学掌握得很棒!</p>
        <button onclick="closeModal('winModal');nextLevel()">进入下一关</button>
    </div>
</div>

<!-- 5.开局关卡选择弹窗(主页) -->
<div class="modal start-modal" id="startModal" style="display:flex;">
    <div class="modal-box">
        <h2>🔢 数字掉落 · 小学数学闯关</h2>
        <p style="margin:12px 0;text-align:center;">选择你要练习的数学关卡:</p>
        <div style="text-align:left;margin:15px 0;line-height:2;">
            <p onclick="startGame(0)" style="cursor:pointer;margin:6px 0;color:#2369a0;">1. 找出所有偶数</p>
            <p onclick="startGame(1)" style="cursor:pointer;margin:6px 0;color:#2369a0;">2. 找出3的倍数</p>
            <p onclick="startGame(2)" style="cursor:pointer;margin:6px 0;color:#2369a0;">3. 找出5的倍数</p>
            <p onclick="startGame(3)" style="cursor:pointer;margin:6px 0;color:#2369a0;">4. 找出质数</p>
            <p onclick="startGame(4)" style="cursor:pointer;margin:6px 0;color:#2369a0;">5. 找出合数</p>
            <p onclick="startGame(5)" style="cursor:pointer;margin:6px 0;color:#2369a0;">6. 找出大于10的数字</p>
        </div>
        <p style="font-size:14px;color:#666;text-align:center;">规则:点击符合条件的数字/算式得分,点错累计失误,3次失误重置关卡,达到目标分即可通关</p>
    </div>
</div>

<script>
// DOM元素获取
const gameArea = document.getElementById('gameArea');
const scoreNum = document.getElementById('scoreNum');
const wrongNum = document.getElementById('wrongNum');
const levelTip = document.getElementById('levelTip');
const noteContent = document.getElementById('noteContent');
const diffTip = document.getElementById('diffTip');
const targetScore = document.getElementById('targetScore');
const highScoreText = document.getElementById('highScoreText');
const homeBtn = document.getElementById('homeBtn');

// 全局游戏变量
let score = 0;
let wrongCount = 0;
let currentLevel = 0;
let isPause = false;
let diffUp = false;
let gameTimer = null;
let fallList = [];
const baseTarget = 100;

// 读取本地最高分
let maxHighScore = Number(localStorage.getItem('mathGameHigh')) || 0;
highScoreText.innerText = maxHighScore;

// 关卡配置
const levelConfig = [
    {
        title:"第1关:找出所有偶数",
        note:"偶数:可以被2整除的整数;个位数字为0、2、4、6、8,例:2、14、20",
        judge:(n)=> n % 2 === 0,
        target: baseTarget
    },
    {
        title:"第2关:找出3的倍数",
        note:"3的倍数:所有数位数字相加的和能被3整除,例:12 → 1+2=3,18 →1+8=9",
        judge:(n)=> n % 3 === 0,
        target: baseTarget + 50
    },
    {
        title:"第3关:找出5的倍数",
        note:"5的倍数:数字个位只能是0或5,例:5、15、30",
        judge:(n)=> n % 5 === 0,
        target: baseTarget + 50
    },
    {
        title:"第4关:找出质数",
        note:"质数:大于1,只能被1和自身整除的数;例:2、3、5、7、11,1不是质数",
        judge:isPrime,
        target: baseTarget + 80
    },
    {
        title:"第5关:找出合数",
        note:"合数:大于1,除1和自身外还有其他因数;例:4、6、8、9,1既不是质数也不是合数",
        judge:(n)=> n>1 && !isPrime(n),
        target: baseTarget + 80
    },
    {
        title:"第6关:找出大于10的数",
        note:"大于10的数字:数值严格超过10,11、12、13…均符合,10及以下不选择",
        judge:(n)=> n > 10,
        target: baseTarget + 30
    }
];

// 质数判断
function isPrime(num){
    if(num<=1) return false;
    for(let i=2;i<=Math.sqrt(num);i++){
        if(num%i===0) return false;
    }
    return true;
}

// 关闭弹窗
function closeModal(id){
    document.getElementById(id).style.display = "none";
}

// 返回主页按钮逻辑
homeBtn.addEventListener('click', ()=>{
    // 清空游戏所有内容
    clearInterval(gameTimer);
    fallList.forEach(el=>el.remove());
    fallList = [];
    diffUp = false;
    diffTip.innerText = "";
    // 重置数据
    score = 0;
    wrongCount = 0;
    scoreNum.innerText = score;
    wrongNum.innerText = wrongCount;
    // 显示主页关卡选择弹窗
    document.getElementById('startModal').style.display = "flex";
});

// 笔记本按钮
document.getElementById('noteBtn').addEventListener('click',()=>{
    const cfg = levelConfig[currentLevel];
    noteContent.innerText = cfg.note;
    document.getElementById('noteModal').style.display = "flex";
});

// 暂停按钮
document.getElementById('pauseBtn').addEventListener('click',()=>{
    isPause = !isPause;
    const btn = document.getElementById('pauseBtn');
    if(isPause){
        btn.innerText = "▶️ 继续";
        clearInterval(gameTimer);
        fallList.forEach(item=>item.style.opacity="0.35");
    }else{
        btn.innerText = "⏸️ 暂停";
        fallList.forEach(item=>item.style.opacity="1");
        startSpawn();
    }
});

// 重置关卡(3次失误)
function resetLevel(){
    wrongCount = 0;
    wrongNum.innerText = wrongCount;
    diffUp = false;
    diffTip.innerText = "";
    fallList.forEach(el=>el.remove());
    fallList = [];
    closeModal('resetModal');
    startSpawn();
}

// 下一关
function nextLevel(){
    currentLevel = (currentLevel + 1) % levelConfig.length;
    score = 0;
    wrongCount = 0;
    scoreNum.innerText = score;
    wrongNum.innerText = wrongCount;
    diffUp = false;
    diffTip.innerText = "";
    fallList.forEach(el=>el.remove());
    fallList = [];
    const cfg = levelConfig[currentLevel];
    levelTip.innerText = cfg.title;
    targetScore.innerText = cfg.target;
    setTimeout(startSpawn,600);
    setTimeout(()=>{
        diffUp = true;
        document.getElementById('diffModal').style.display = "flex";
        diffTip.innerText = "【难度升级:数字+算式混合】";
    },20000);
}

// 开始选中关卡
function startGame(levelIdx){
    currentLevel = levelIdx;
    const cfg = levelConfig[currentLevel];
    levelTip.innerText = cfg.title;
    targetScore.innerText = cfg.target;
    score = 0;
    wrongCount = 0;
    scoreNum.innerText = score;
    wrongNum.innerText = wrongCount;
    diffUp = false;
    diffTip.innerText = "";
    fallList.forEach(el=>el.remove());
    fallList = [];
    closeModal('startModal');
    setTimeout(startSpawn,600);
    setTimeout(()=>{
        diffUp = true;
        document.getElementById('diffModal').style.display = "flex";
        diffTip.innerText = "【难度升级:数字+算式混合】";
    },20000);
}

// 随机数字1~30
function randNum(){
    return Math.floor(Math.random()*30)+1;
}

// 生成加减乘除算式
function createFormula(){
    const a = randNum();
    const b = randNum();
    const ops = ["+","-","*"];
    const op = ops[Math.floor(Math.random()*3)];
    let res;
    let text = a + op + b;
    switch(op){
        case "+": res = a + b; break;
        case "-": res = a - b; break;
        case "*": res = a * b; break;
    }
    return {text, res};
}

// 创建下落元素(速度已调低:1 ~ 2.2)
function createFallItem(){
    if(isPause) return;
    const item = document.createElement('div');
    item.className = "fall-item";
    let value;
    if(diffUp && Math.random() > 0.5){
        const formula = createFormula();
        item.innerText = formula.text;
        value = formula.res;
    }else{
        value = randNum();
        item.innerText = value;
    }
    const maxX = window.innerWidth - 90;
    const x = Math.random() * maxX;
    item.style.left = x + "px";
    item.style.top = "-65px";
    gameArea.appendChild(item);
    fallList.push(item);

    // 核心修改:下落速度大幅降低
    const fallSpeed = 1 + Math.random() * 1.2;
    function fallLoop(){
        if(isPause) return;
        let top = parseFloat(item.style.top);
        top += fallSpeed;
        item.style.top = top + "px";
        if(top > window.innerHeight){
            item.remove();
            fallList = fallList.filter(el => el !== item);
            return;
        }
        requestAnimationFrame(fallLoop);
    }
    fallLoop();

    // 点击判断
    item.addEventListener('click',()=>{
        const cfg = levelConfig[currentLevel];
        if(cfg.judge(value)){
            score += value;
            scoreNum.innerText = score;
            item.style.background = "rgba(46, 204, 113, 0.85)";
            if(score >= cfg.target){
                clearInterval(gameTimer);
                if(score > maxHighScore){
                    maxHighScore = score;
                    localStorage.setItem('mathGameHigh',maxHighScore);
                    highScoreText.innerText = maxHighScore;
                }
                document.getElementById('winModal').style.display = "flex";
            }
        }else{
            wrongCount++;
            wrongNum.innerText = wrongCount;
            item.style.background = "rgba(231, 76, 60, 0.85)";
            if(wrongCount >= 3){
                clearInterval(gameTimer);
                document.getElementById('resetModal').style.display = "flex";
            }
        }
        setTimeout(()=>{
            item.remove();
            fallList = fallList.filter(el => el !== item);
        },180);
    })
}

// 生成物体定时器
function startSpawn(){
    clearInterval(gameTimer);
    gameTimer = setInterval(createFallItem,700);
}
</script>
</body>
</html>

Game Source: 数字掉落 - 小学数学闯关小游戏

Creator: SonicStar40

Libraries: none

Complexity: complex (417 lines, 14.5 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-sonicstar40" to link back to the original. Then publish at arcadelab.ai/publish.