🎮ArcadeLab

全域Emoji打怪(低负载)

by NovaStar20
223 lines6.8 KB
▶ Play
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<title>全域Emoji打怪(低负载)</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;font-size:18px;}
body{background:#0a0a18;color:#fff;height:100vh;overflow:hidden;touch-action:none;}
#startPage{width:100%;height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:24px;}
#gamePage{width:100%;height:100vh;display:none;position:relative;}
.info-bar{padding:10px;text-align:center;z-index:10;position:relative;}
#gameArea{width:100%;height:72vh;background:#111428;position:relative;overflow:hidden;}
.player{font-size:48px;position:absolute;z-index:2;user-select:none;}
.gun-item{font-size:40px;position:absolute;z-index:1;user-select:none;}
.monster{font-size:42px;position:absolute;user-select:none;}
.joystick-box{position:absolute;bottom:12px;left:16px;width:120px;height:120px;background:rgba(255,255,255,0.15);border-radius:50%;}
.joystick-stick{width:46px;height:46px;background:rgba(255,255,255,0.35);border-radius:50%;position:absolute;left:37px;top:37px;}
</style>
</head>
<body>
<div id="startPage">
    <div style="font-size:34px">😃 全域打怪</div>
    <div>摇杆自由移动,拾取枪械点击消灭怪物</div>
    <button onclick="startGame()" style="font-size:22px;padding:14px 32px">开始游戏</button>
</div>

<div id="gamePage">
    <div class="info-bar">
        分数:<span id="scoreTxt">0</span>|生命:<span id="hpTxt">❤️❤️❤️</span>
    </div>
    <div id="gameArea">
        <div class="player" id="player">😃</div>
        <div class="gun-item" id="gunItem">🔫</div>
    </div>
    <div class="joystick-box" id="joyBox">
        <div class="joystick-stick" id="joyStick"></div>
    </div>
</div>

<script>
let score = 0;
let hp = 3;
let playerX = 45;
let playerY = 60;
const playerSpeed = 0.36;
let gameRun = false;
let hasGun = false;
let monsterList = [];
const MAX_MONSTER = 8;

let joyActive = false;
let joyVecX = 0;
let joyVecY = 0;

const gameArea = document.getElementById('gameArea');
const playerDom = document.getElementById('player');
const gunItem = document.getElementById('gunItem');
const scoreTxt = document.getElementById('scoreTxt');
const hpTxt = document.getElementById('hpTxt');
const joyBox = document.getElementById('joyBox');
const joyStick = document.getElementById('joyStick');

function resetGame(){
    score = 0;
    hp = 3;
    playerX = 45;
    playerY = 60;
    hasGun = false;
    monsterList = [];
    gunItem.style.display = "block";
    gunItem.style.left = playerX + "%";
    gunItem.style.top = (playerY + 12) + "%";
    document.querySelectorAll('.monster').forEach(el=>el.remove());
    refreshUI();
}

function refreshUI(){
    scoreTxt.innerText = score;
    hpTxt.innerText = "❤️".repeat(hp);
    playerDom.style.left = playerX + "%";
    playerDom.style.top = playerY + "%";
}

function startGame(){
    document.getElementById('startPage').style.display="none";
    document.getElementById('gamePage').style.display="block";
    resetGame();
    gameRun=true;
    loop();
    setTimeout(spawnMonster,6000);
}

joyBox.addEventListener('touchstart',()=>{joyActive=true;});
joyBox.addEventListener('touchmove',e=>{
    e.preventDefault();
    const touch = e.touches[0];
    const rect = joyBox.getBoundingClientRect();
    const cx = 60, cy = 60;
    let dx = touch.clientX - rect.left - cx;
    let dy = touch.clientY - rect.top - cy;
    const maxR = 50;
    const dist = Math.hypot(dx,dy);
    if(dist > maxR){
        dx = dx/dist * maxR;
        dy = dy/dist * maxR;
    }
    joyStick.style.left = (cx + dx - 23) + "px";
    joyStick.style.top = (cy + dy - 23) + "px";
    joyVecX = dx / maxR;
    joyVecY = dy / maxR;
});
joyBox.addEventListener('touchend',()=>{
    joyActive=false;
    joyVecX = 0;
    joyVecY = 0;
    joyStick.style.left="37px";
    joyStick.style.top="37px";
});

gameArea.addEventListener('touchstart',(evt)=>{
    if(!gameRun || !hasGun) return;
    const rect = gameArea.getBoundingClientRect();
    const clickX = (evt.touches[0].clientX - rect.left)/rect.width*100;
    const clickY = (evt.touches[0].clientY - rect.top)/rect.height*100;
    for(let i = monsterList.length - 1; i >= 0; i--){
        const m = monsterList[i];
        const distance = Math.hypot(clickX - m.x, clickY - m.y);
        if(distance < 6){
            score += 10;
            m.dom.remove();
            monsterList.splice(i,1);
            refreshUI();
            break;
        }
    }
});

function spawnMonster(){
    if(!gameRun) return;
    if(monsterList.length >= MAX_MONSTER){
        setTimeout(spawnMonster, 1800);
        return;
    }
    const emoji = ["😈","😡"][Math.floor(Math.random()*2)];
    let x,y;
    const side = Math.floor(Math.random()*4);
    switch(side){
        case 0: x = Math.random()*100; y = -6; break;
        case 1: x = Math.random()*100; y = 98; break;
        case 2: x = -6; y = Math.random()*100; break;
        case 3: x = 102; y = Math.random()*100; break;
    }
    const monsterDom = document.createElement('div');
    monsterDom.className = "monster";
    monsterDom.innerText = emoji;
    monsterDom.style.left = x + "%";
    monsterDom.style.top = y + "%";
    gameArea.appendChild(monsterDom);
    monsterList.push({
        dom:monsterDom,
        x:x,
        y:y,
        speed:0.22
    });
    setTimeout(spawnMonster, 1800);
}

function loop(){
    if(!gameRun) return;
    let needUpdate = false;

    if(joyActive){
        playerX += joyVecX * playerSpeed;
        playerY += joyVecY * playerSpeed;
        playerX = Math.max(3, Math.min(93, playerX));
        playerY = Math.max(3, Math.min(88, playerY));
        needUpdate = true;
    }

    if(!hasGun){
        const gx = parseFloat(gunItem.style.left);
        const gy = parseFloat(gunItem.style.top);
        const distGun = Math.hypot(playerX-gx, playerY-gy);
        if(distGun < 6){
            hasGun = true;
            gunItem.style.display = "none";
        }
    }

    for(let i = monsterList.length - 1; i >= 0; i--){
        const m = monsterList[i];
        const dx = playerX - m.x;
        const dy = playerY - m.y;
        const dist = Math.hypot(dx,dy);
        if(dist > 0.5){
            m.x += dx/dist * m.speed;
            m.y += dy/dist * m.speed;
        }
        m.dom.style.left = m.x + "%";
        m.dom.style.top = m.y + "%";

        const hitDist = Math.hypot(playerX - m.x, playerY - m.y);
        if(hitDist < 5){
            hp--;
            needUpdate = true;
            m.dom.remove();
            monsterList.splice(i,1);
            if(hp <= 0){
                gameRun = false;
                alert("游戏结束!得分:"+score);
                setTimeout(resetGame, 1200);
            }
        }
    }

    if(needUpdate) refreshUI();
    requestAnimationFrame(loop);
}
</script>
</body>
</html>

Game Source: 全域Emoji打怪(低负载)

Creator: NovaStar20

Libraries: none

Complexity: complex (223 lines, 6.8 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: emoji-novastar20" to link back to the original. Then publish at arcadelab.ai/publish.