雙人數學大逃殺|苦力怕版 HTML5|可調數學難度 + 作弊功能
by SparkShark50890 lines24.0 KB
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<!-- HTML5 viewport 手機適配 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>雙人數學大逃殺|苦力怕版 HTML5|可調數學難度 + 作弊功能</title>
<style>
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:monospace;
}
body{
background:#111;
min-height:100vh;
overflow:hidden;
}
#gameCanvas{
display:block;
background:#3a3a2a;
}
/* ========== 開始畫面 ========== */
#startScreen{
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background:
radial-gradient(circle at 30% 20%, rgba(255,120,0,0.25), transparent 45%),
radial-gradient(circle at 70% 80%, rgba(0,0,0,0.6), transparent 55%),
linear-gradient(180deg,#1a1a1a,#2a2a2a);
display:flex;
justify-content:center;
align-items:center;
z-index:100;
}
.startBox{
text-align:center;
color:#fff;
padding:26px;
border:2px solid rgba(255,160,0,0.5);
background:rgba(0,0,0,0.55);
border-radius:14px;
box-shadow:0 0 40px rgba(255,140,0,0.25);
max-width:460px;
max-height:95vh;
overflow-y:auto;
}
.startBox h2{
font-size:26px;
letter-spacing:3px;
color:#ffb04d;
text-shadow:0 0 12px rgba(255,140,0,0.6);
margin-bottom:10px;
}
.startBox p{
font-size:14px;
color:#ddd;
margin-bottom:12px;
line-height:1.6;
}
.settingBlock{
margin:12px 0;
padding:10px;
border:1px solid rgba(255,160,0,0.35);
border-radius:8px;
text-align:left;
}
.settingBlock h4{
color:#ffb04d;
margin-bottom:8px;
font-size:16px;
}
.optionItem{
margin:4px;
font-size:14px;
}
#startBtn{
font-size:22px;
padding:12px 30px;
cursor:pointer;
background:linear-gradient(180deg,#ff8800,#c44400);
color:#fff;
border:2px solid #ffaa33;
border-radius:10px;
letter-spacing:2px;
z-index:101;
margin-top:8px;
}
#startBtn:active{
transform:scale(0.96);
}
/* ========== 遊戲 UI ========== */
#ui{
position:absolute;
top:10px;
left:10px;
color:#fff;
font-size:14px;
background:rgba(0,0,0,0.6);
padding:10px 12px;
z-index:5;
border-left:3px solid #ff9900;
border-radius:4px;
line-height:1.6;
}
#ui .p1{
color:#ff7777;
}
#ui .p2{
color:#77aaff;
}
#zoneWarning{
position:absolute;
top:80px;
left:50%;
transform:translateX(-50%);
color:#ff4444;
font-size:18px;
font-weight:bold;
background:rgba(0,0,0,0.6);
padding:6px 12px;
border-radius:6px;
display:none;
z-index:6;
letter-spacing:2px;
}
/* ========== 虛擬按鈕|玩家1(左邊) ========== */
#p1Control{
position:absolute;
bottom:20px;
left:20px;
z-index:10;
}
.vBtn{
width:60px;
height:60px;
font-size:24px;
margin:3px;
background:rgba(255,255,255,0.08);
color:#fff;
border:2px solid rgba(255,160,0,0.45);
border-radius:12px;
touch-action:none;
}
.vBtn:active{
background:rgba(255,140,0,0.45);
}
#p1FireBtn,#p1PotionBtn{
position:absolute;
bottom:20px;
right:20px;
width:70px;
height:70px;
font-size:22px;
background:rgba(255,60,60,0.25);
color:#fff;
border:2px solid rgba(255,90,90,0.5);
border-radius:50%;
touch-action:none;
}
#p1FireBtn:active,#p1PotionBtn:active{
background:rgba(255,90,90,0.55);
}
#p1PotionBtn{
bottom:105px;
background:rgba(80,160,255,0.25);
border-color:rgba(110,180,255,0.5);
}
/* ========== 虛擬按鈕|玩家2(右中) ========== */
#p2Control{
position:absolute;
bottom:20px;
right:130px;
z-index:10;
}
#p2FireBtn,#p2PotionBtn{
position:absolute;
bottom:20px;
left:20px;
width:70px;
height:70px;
font-size:22px;
background:rgba(60,120,255,0.25);
color:#fff;
border:2px solid rgba(90,140,255,0.5);
border-radius:50%;
touch-action:none;
}
#p2FireBtn:active,#p2PotionBtn:active{
background:rgba(90,140,255,0.55);
}
#p2PotionBtn{
bottom:105px;
background:rgba(80,220,160,0.25);
border-color:rgba(110,240,180,0.5);
}
/* ========== 數學題彈窗 ========== */
#mathPanel{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
background:linear-gradient(180deg,#1c1c1c,#2a2a2a);
color:#fff;
padding:26px;
font-size:26px;
display:none;
z-index:50;
text-align:center;
border:2px solid #ff9900;
border-radius:12px;
box-shadow:0 0 30px rgba(255,140,0,0.35);
min-width:310px;
}
#mathPanel .tip{
font-size:14px;
color:#ffb04d;
margin-bottom:10px;
letter-spacing:1px;
}
#mathInput{
font-size:24px;
width:140px;
padding:8px;
margin:12px 8px;
text-align:center;
background:#000;
color:#fff;
border:2px solid #ff9900;
border-radius:6px;
}
#submitMath{
font-size:18px;
padding:8px 16px;
cursor:pointer;
background:#ff8800;
color:#fff;
border:none;
border-radius:6px;
}
/* ========== GameOver / 排行榜 ========== */
#gameOverPanel{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
background:linear-gradient(180deg,#141414,#222);
color:#fff;
padding:26px;
display:none;
z-index:60;
text-align:center;
border:2px solid #ff4444;
border-radius:14px;
min-width:330px;
}
#gameOverPanel h3{
color:#ff6666;
margin-bottom:10px;
letter-spacing:2px;
}
#gameOverPanel input{
display:block;
margin:8px auto;
padding:8px;
width:80%;
background:#000;
color:#fff;
border:1px solid #ff9900;
border-radius:4px;
}
#gameOverPanel button{
font-size:16px;
padding:10px 16px;
cursor:pointer;
background:#ff8800;
color:#fff;
border:none;
border-radius:6px;
}
</style>
</head>
<body>
<!-- 開始畫面|所有設定 -->
<div id="startScreen">
<div class="startBox">
<h2>雙人數學大逃殺|苦力怕版 HTML5</h2>
<p>👤玩家1:WASD / 左下角虛擬方向鍵<br>👤玩家2:方向鍵 / 右中虛擬方向鍵<br>擊敗苦力怕後答數學題,可按Enter提交答案!<br>💻電腦鍵盤作弊:Q回滿HP|E+500分|R清苦力怕|T加速|Y關毒圈</p>
<div class="settingBlock">
<h4>🎯 敵人出生距離</h4>
<div class="optionItem">
<input type="radio" name="enemyDist" id="distNear" value="near">
<label for="distNear">近距離|難</label>
</div>
<div class="optionItem">
<input type="radio" name="enemyDist" id="distMid" value="mid" checked>
<label for="distMid">中距離|正常</label>
</div>
<div class="optionItem">
<input type="radio" name="enemyDist" id="distFar" value="far">
<label for="distFar">遠距離|易</label>
</div>
</div>
<div class="settingBlock">
<h4>🔫 選擇槍種(兩位玩家共用槍型)</h4>
<div class="optionItem">
<input type="radio" name="gunType" id="gunNormal" value="normal" checked>
<label for="gunNormal">普通步槍|平衡</label>
</div>
<div class="optionItem">
<input type="radio" name="gunType" id="gunSniper" value="sniper">
<label for="gunSniper">狙擊槍|子彈快</label>
</div>
<div class="optionItem">
<input type="radio" name="gunType" id="gunShotgun" value="shotgun">
<label for="gunShotgun">霰彈槍|大子彈</label>
</div>
</div>
<!-- ✅ 新:數學難度選擇 -->
<div class="settingBlock">
<h4>🧮 數學題難度</h4>
<div class="optionItem">
<input type="radio" name="mathDiff" id="mathEasy" value="easy" checked>
<label for="mathEasy">簡單|1–10 加法</label>
</div>
<div class="optionItem">
<input type="radio" name="mathDiff" id="mathNormal" value="normal">
<label for="mathNormal">普通|1–20 加減(無負數)</label>
</div>
<div class="optionItem">
<input type="radio" name="mathDiff" id="mathHard" value="hard">
<label for="mathHard">困難|1–12 乘法</label>
</div>
<div class="optionItem">
<input type="radio" name="mathDiff" id="mathExtreme" value="extreme">
<label for="mathExtreme">極難|加減乘混合</label>
</div>
</div>
<button id="startBtn">開始雙人比賽</button>
</div>
</div>
<!-- ✅ HTML5 Canvas 遊戲畫布 -->
<canvas id="gameCanvas"></canvas>
<!-- 📱 玩家1虛擬方向鍵(左下角) -->
<div id="p1Control">
<div>
<button class="vBtn" id="p1Up">↑</button>
</div>
<div>
<button class="vBtn" id="p1Left">←</button>
<button class="vBtn" id="p1Down">↓</button>
<button class="vBtn" id="p1Right">→</button>
</div>
</div>
<button id="p1FireBtn">🗡️</button>
<button id="p1PotionBtn">💊</button>
<!-- 📱 玩家2虛擬方向鍵(右中) -->
<div id="p2Control">
<div>
<button class="vBtn" id="p2Up">↑</button>
</div>
<div>
<button class="vBtn" id="p2Left">←</button>
<button class="vBtn" id="p2Down">↓</button>
<button class="vBtn" id="p2Right">→</button>
</div>
</div>
<button id="p2FireBtn">🗡️</button>
<button id="p2PotionBtn">💊</button>
<!-- 遊戲 UI -->
<div id="ui">
<div class="p1">🔴玩家1</div>
<div>❤️HP:<span id="p1hp">100</span>|⭐分數:<span id="p1score">0</span>|📈Lv.<span id="p1lv">1</span></div>
<br>
<div class="p2">🔵玩家2</div>
<div>❤️HP:<span id="p2hp">100</span>|⭐分數:<span id="p2score">0</span>|📈Lv.<span id="p2lv">1</span></div>
<div>⏱️時間:<span id="timeLeft">90</span>s|🔵安全區:<span id="safeZone">320</span>m</div>
</div>
<div id="zoneWarning">⚠️ 縮圈外!扣緊HP!</div>
<!-- 數學題彈窗 -->
<div id="mathPanel">
<div class="tip">✅ 擊敗苦力怕!答對就可以升級!(可按Enter提交)</div>
<div id="mathQ"></div>
<input type="number" id="mathInput" inputmode="numeric">
<br>
<button id="submitMath">提交答案</button>
</div>
<!-- GameOver + 排行榜輸入 -->
<div id="gameOverPanel">
<h3>🏁 比賽完結</h3>
<p>🔴玩家1分數:<span id="finalP1"></span></p>
<p>🔵玩家2分數:<span id="finalP2"></span></p>
<p id="winnerText"></p>
<input type="text" id="playerName" placeholder="輸入參賽者名字">
<input type="text" id="playerClass" placeholder="輸入班級">
<br>
<button id="saveRank">儲存紀錄</button>
</div>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let gameStart = false;
let startScreen = document.getElementById("startScreen");
let startBtn = document.getElementById("startBtn");
let gameTimer = null;
let isStarting = false; // ✅ 修復開始按鈕防重複觸發
let mathDifficulty = "easy";
let noSafeZoneShrink = false; // ✅ 外掛:關閉毒圈縮圈
const GAME_DURATION = 90;
let timeLeft = GAME_DURATION;
// 雙玩家資料
let p1 = {
x: canvas.width*0.35,
y: canvas.height/2,
w:40, h:40,
hp:100, score:0, level:1, speed:2,
keys:{w:false,a:false,s:false,d:false}
};
let p2 = {
x: canvas.width*0.65,
y: canvas.height/2,
w:40, h:40,
hp:100, score:0, level:1, speed:2,
keys:{up:false,left:false,down:false,right:false}
};
let enemyMinSpawnDist = 220;
let gunConfig = {bulletSpeed:6, bulletSize:6};
//安全圈
let safeZoneRadius = Math.min(canvas.width, canvas.height)*0.45;
const safeZoneCenter = {x:canvas.width/2, y:canvas.height/2};
let bullets = [];
let enemies = [];
let pausedForMath = false;
let currentPlayerForMath = null;
// ========== 虛擬按鈕事件綁定函數 ==========
function bindTouch(btn, playerKeyObj, keyName){
btn.addEventListener("touchstart", (e)=>{ e.preventDefault(); playerKeyObj[keyName]=true; })
btn.addEventListener("touchend", (e)=>{ e.preventDefault(); playerKeyObj[keyName]=false; })
}
// P1方向掣
bindTouch(document.getElementById("p1Up"), p1.keys, "w");
bindTouch(document.getElementById("p1Down"), p1.keys, "s");
bindTouch(document.getElementById("p1Left"), p1.keys, "a");
bindTouch(document.getElementById("p1Right"), p1.keys, "d");
// P2方向掣
bindTouch(document.getElementById("p2Up"), p2.keys, "up");
bindTouch(document.getElementById("p2Down"), p2.keys, "down");
bindTouch(document.getElementById("p2Left"), p2.keys, "left");
bindTouch(document.getElementById("p2Right"), p2.keys, "right");
// P1射擊、藥水
document.getElementById("p1FireBtn").addEventListener("touchstart",(e)=>{
e.preventDefault();
if(gameStart && !pausedForMath) shootBullet(p1);
})
document.getElementById("p1PotionBtn").addEventListener("touchstart",(e)=>{
e.preventDefault();
if(gameStart && !pausedForMath){
p1.hp = Math.min(100, p1.hp + 30);
updateUI();
}
})
// P2射擊、藥水
document.getElementById("p2FireBtn").addEventListener("touchstart",(e)=>{
e.preventDefault();
if(gameStart && !pausedForMath) shootBullet(p2);
})
document.getElementById("p2PotionBtn").addEventListener("touchstart",(e)=>{
e.preventDefault();
if(gameStart && !pausedForMath){
p2.hp = Math.min(100, p2.hp + 30);
updateUI();
}
})
// ========== 鍵盤偵測 + ✅ 外掛按鍵 ==========
document.addEventListener("keydown",(e)=>{
if(!gameStart || pausedForMath) return;
const k = e.key.toLowerCase();
// P1 WASD
if(k==='w') p1.keys.w=true;
if(k==='a') p1.keys.a=true;
if(k==='s') p1.keys.s=true;
if(k==='d') p1.keys.d=true;
// P2 方向鍵
if(k==='arrowup') p2.keys.up=true;
if(k==='arrowleft') p2.keys.left=true;
if(k==='arrowdown') p2.keys.down=true;
if(k==='arrowright') p2.keys.right=true;
// ✅ 外掛指令
if(k === 'q'){
p1.hp = 100; p2.hp = 100;
}
if(k === 'e'){
p1.score +=500; p2.score +=500;
}
if(k === 'r'){
enemies = [];
}
if(k === 't'){
p1.speed +=2; p2.speed +=2;
}
if(k === 'y'){
noSafeZoneShrink = !noSafeZoneShrink;
}
updateUI();
})
document.addEventListener("keyup",(e)=>{
const k = e.key.toLowerCase();
if(k==='w') p1.keys.w=false;
if(k==='a') p1.keys.a=false;
if(k==='s') p1.keys.s=false;
if(k==='d') p1.keys.d=false;
if(k==='arrowup') p2.keys.up=false;
if(k==='arrowleft') p2.keys.left=false;
if(k==='arrowdown') p2.keys.down=false;
if(k==='arrowright') p2.keys.right=false;
})
// 空格射擊P1
document.addEventListener("keydown",(e)=>{
if(e.code==='Space' && gameStart && !pausedForMath){
shootBullet(p1);
}
})
function shootBullet(player){
let target = getNearestEnemy();
if(!target) return;
const dx = target.x - player.x;
const dy = target.y - player.y;
const dist = Math.hypot(dx,dy);
bullets.push({
x:player.x, y:player.y,
vx: (dx/dist)*gunConfig.bulletSpeed,
vy: (dy/dist)*gunConfig.bulletSpeed,
r: gunConfig.bulletSize,
owner: player
})
}
function getNearestEnemy(){
if(enemies.length===0) return null;
let nearest = enemies[0];
let minD = Infinity;
for(let e of enemies){
let d = Math.hypot(e.x-canvas.width/2, e.y-canvas.height/2);
if(d<minD){ minD=d; nearest=e; }
}
return nearest;
}
// ========== 初始化遊戲 ==========
function initGame(){
p1.hp=100; p1.score=0; p1.level=1; p1.speed=2;
p2.hp=100; p2.score=0; p2.level=1; p2.speed=2;
timeLeft = GAME_DURATION;
safeZoneRadius = Math.min(canvas.width, canvas.height)*0.45;
bullets = []; enemies = [];
pausedForMath = false;
noSafeZoneShrink = false;
updateUI();
}
// ========== 開始遊戲 ✅ 修復防重複Bug ==========
function startGame(e){
if(isStarting || gameStart) return;
isStarting = true;
if(gameTimer){ clearInterval(gameTimer); gameTimer=null; }
if(e) e.preventDefault();
//讀敵人距離設定
if(document.getElementById("distNear").checked) enemyMinSpawnDist = 100;
else if(document.getElementById("distMid").checked) enemyMinSpawnDist = 220;
else if(document.getElementById("distFar").checked) enemyMinSpawnDist = 400;
//讀槍設定
const gunSel = document.querySelector('input[name="gunType"]:checked').value;
if(gunSel==="normal") gunConfig = {bulletSpeed:6, bulletSize:6};
else if(gunSel==="sniper") gunConfig = {bulletSpeed:11, bulletSize:5};
else if(gunSel==="shotgun") gunConfig = {bulletSpeed:4, bulletSize:10};
//讀數學難度
mathDifficulty = document.querySelector('input[name="mathDiff"]:checked').value;
gameStart = true;
startScreen.style.display = "none";
initGame();
gameTimer = setInterval(()=>{
if(!gameStart){ clearInterval(gameTimer); gameTimer=null; return; }
if(pausedForMath) return;
timeLeft--;
if(!noSafeZoneShrink){
safeZoneRadius -=0.4;
if(safeZoneRadius<80) safeZoneRadius=80;
}
updateUI();
if(timeLeft<=0) showGameOver();
},1000);
setTimeout(()=>{ isStarting = false; },300);
}
startBtn.addEventListener("click", startGame);
startBtn.addEventListener("touchstart", startGame, {passive:false});
function updateUI(){
document.getElementById("p1hp").innerText = Math.round(p1.hp);
document.getElementById("p1score").innerText = p1.score;
document.getElementById("p1lv").innerText = p1.level;
document.getElementById("p2hp").innerText = Math.round(p2.hp);
document.getElementById("p2score").innerText = p2.score;
document.getElementById("p2lv").innerText = p2.level;
document.getElementById("timeLeft").innerText = timeLeft;
document.getElementById("safeZone").innerText = Math.round(safeZoneRadius);
}
// ========== 生成苦力怕敵人 ==========
function spawnEnemy(){
let ex,ey,valid=false;
while(!valid){
const side = Math.floor(Math.random()*4);
if(side===0){ ex=Math.random()*canvas.width; ey=-40; }
else if(side===1){ ex=canvas.width+40; ey=Math.random()*canvas.height; }
else if(side===2){ ex=Math.random()*canvas.width; ey=canvas.height+40; }
else { ex=-40; ey=Math.random()*canvas.height; }
const d1 = Math.hypot(ex-p1.x, ey-p1.y);
const d2 = Math.hypot(ex-p2.x, ey-p2.y);
if(d1 >= enemyMinSpawnDist && d2 >= enemyMinSpawnDist) valid=true;
}
enemies.push({x:ex,y:ey,w:44,h:52,speed:0.6})
}
// ========== 繪畫苦力怕像素樣子 ==========
function drawCreeper(e){
// 苦力怕主體綠色
ctx.fillStyle="#569C48";
ctx.fillRect(e.x, e.y, e.w, e.h);
// 深色斑紋
ctx.fillStyle="#3C6E34";
ctx.fillRect(e.x+8, e.y+8, 12,12);
ctx.fillRect(e.x+24, e.y+8, 12,12);
ctx.fillRect(e.x+14, e.y+26,16,12);
ctx.fillStyle="#222";
ctx.fillRect(e.x+10, e.y+10,8,8);
ctx.fillRect(e.x+26, e.y+10,8,8);
}
// ========== 數學題 & 升級(可選難度) ==========
const mathPanel = document.getElementById("mathPanel");
const mathQ = document.getElementById("mathQ");
const mathInput = document.getElementById("mathInput");
const submitMath = document.getElementById("submitMath");
let mathAnswer;
function openMathQuestion(whoHit){
pausedForMath = true;
currentPlayerForMath = whoHit;
let a,b,op;
if(mathDifficulty === "easy"){
a = Math.floor(Math.random()*10)+1;
b = Math.floor(Math.random()*10)+1;
op = "+";
mathAnswer = a+b;
}else if(mathDifficulty === "normal"){
a = Math.floor(Math.random()*20)+1;
b = Math.floor(Math.random()*20)+1;
if(Math.random()>0.5){
op="+"; mathAnswer=a+b;
}else{
if(a<b){let t=a;a=b;b=t;}
op="-"; mathAnswer=a-b;
}
}else if(mathDifficulty === "hard"){
a = Math.floor(Math.random()*12)+1;
b = Math.floor(Math.random()*12)+1;
op="×";
mathAnswer = a*b;
}else if(mathDifficulty === "extreme"){
const r = Math.random();
if(r<0.33){
a = Math.floor(Math.random()*20)+1; b = Math.floor(Math.random()*20)+1; op="+"; mathAnswer=a+b;
}else if(r<0.66){
a = Math.floor(Math.random()*20)+1; b = Math.floor(Math.random()*20)+1; if(a<b){let t=a;a=b;b=t;} op="-"; mathAnswer=a-b;
}else{
a = Math.floor(Math.random()*12)+1; b = Math.floor(Math.random()*12)+1; op="×"; mathAnswer=a*b;
}
}
mathQ.innerText = `${a} ${op} ${b} = ?`;
mathPanel.style.display = "block";
mathInput.value = "";
// ✅ 自動聚焦,手機彈數字鍵盤
mathInput.focus();
}
// ✅ Enter鍵提交答案
mathInput.addEventListener("keydown", (e)=>{
if(e.code === "Enter") submitMath.click();
})
submitMath.onclick = ()=>{
if(Number(mathInput.value) === mathAnswer){
currentPlayerForMath.score +=100;
currentPlayerForMath.level +=1;
currentPlayerForMath.speed +=0.15;
}
mathPanel.style.display = "none";
pausedForMath = false;
currentPlayerForMath = null;
updateUI();
}
// ========== GameOver ==========
const gameOverPanel = document.getElementById("gameOverPanel");
const saveRankBtn = document.getElementById("saveRank");
const finalP1 = document.getElementById("finalP1");
const finalP2 = document.getElementById("finalP2");
const winnerText = document.getElementById("winnerText");
function showGameOver(){
gameStart = false;
if(gameTimer){ clearInterval(gameTimer); gameTimer=null; }
finalP1.innerText = p1.score;
finalP2.innerText = p2.score;
if(p1.score>p2.score) winnerText.innerText = "🏆 玩家1勝出!";
else if(p2.score>p1.score) winnerText.innerText = "🏆 玩家2勝出!";
else winnerText.innerText = "🤝 雙方平手!";
gameOverPanel.style.display = "block";
}
saveRankBtn.onclick = ()=>{
const name = document.getElementById("playerName").value.trim();
const cls = document.getElementById("playerClass").value.trim();
if(!name) return;
let rankList = JSON.parse(localStorage.getItem("pubgMathRank")) || [];
const weekKey = new Date().getFullYear()+"-"+Math.floor(new Date().getTime()/(7*24*60*60*1000));
const savedWeek = localStorage.getItem("rankWeekKeyPubg");
if(savedWeek !== weekKey){ rankList = []; localStorage.setItem("rankWeekKeyPubg", weekKey); }
rankList.push({name, cls, p1score:p1.score, p2score:p2.score});
rankList.sort((a,b)=>Math.max(b.p1score,b.p2score)-Math.max(a.p1score,a.p2score));
rankList = rankList.slice(0,100);
localStorage.setItem("pubgMathRank", JSON.stringify(rankList));
gameOverPanel.style.display = "none";
}
// ========== 主遊戲迴圈 ==========
let spawnTimer = 0;
function gameLoop(){
ctx.clearRect(0,0,canvas.width,canvas.height);
//畫安全圈
ctx.beginPath();
ctx.arc(safeZoneCenter.x, safeZoneCenter.y, safeZoneRadius,0,Math.PI*2);
ctx.fillStyle = "rgba(60,100,180,0.18)";
ctx.fill();
ctx.strokeStyle="#4488ff";
ctx.lineWidth=3;
ctx.stroke();
if(gameStart && !pausedForMath){
// P1移動
if(p1.keys.w) p1.y -= p1.speed;
if(p1.keys.s) p1.y += p1.speed;
if(p1.keys.a) p1.x -= p1.speed;
if(p1.keys.d) p1.x += p1.speed;
// P2移動
if(p2.keys.up) p2.y -= p2.speed;
if(p2.keys.down) p2.y += p2.speed;
if(p2.keys.left) p2.x -= p2.speed;
if(p2.keys.right) p2.x += p2.speed;
//毒圈扣血
const warnEl = document.getElementById("zoneWarning");
const dSafe1 = Math.hypot(p1.x-safeZoneCenter.x, p1.y-safeZoneCenter.y);
const dSafe2 = Math.hypot(p2.x-safeZoneCenter.x, p2.y-safeZoneCenter.y);
if(dSafe1>safeZoneRadius || dSafe2>safeZoneRadius){
warnEl.style.display="block";
if(!noSafeZoneShrink){
if(dSafe1>safeZoneRadius) p1.hp -=0.08;
if(dSafe2>safeZoneRadius) p2.hp -=0.08;
}
}else{
warnEl.style.display="none";
}
//生成敵人
spawnTimer++;
if(spawnTimer>120){ spawnEnemy(); spawnTimer=0; }
//更新子彈
for(let i=bullets.length-1;i>=0;i--){
const b = bullets[i];
b.x += b.vx; b.y += b.vy;
ctx.beginPath();
ctx.arc(b.x,b.y,b.r,0,Math.PI*2);
ctx.fillStyle="#ff2222";
ctx.fill();
if(b.x<0||b.x>canvas.width||b.y<0||b.y>canvas.height) bullets.splice(i,1);
}
//更新苦力怕敵人
for(let i=enemies.length-1;i>=0;i--){
const e = enemies[i];
const dToP1 = Math.hypot(e.x-p1.x, e.y-p1.y);
const dToP2 = Math.hypot(e.x-p2.x, e.y-p2.y);
let targetPlayer = dToP1 < dToP2 ? p1 : p2;
const dx = targetPlayer.x - e.x;
const dy = targetPlayer.y - e.y;
const dist = Math.hypot(dx,dy);
e.x += (dx/dist)*e.speed;
e.y += (dy/dist)*e.speed;
// ✅ 繪畫苦力怕
drawCreeper(e);
//子彈擊中苦力怕
for(let j=bullets.length-1;j>=0;j--){
const b = bullets[j];
const hitD = Math.hypot(b.x-e.x, b.y-e.y);
if(hitD < 45){
enemies.splice(i,1);
bullets.splice(j,1);
openMathQuestion(b.owner);
break;
}
}
//苦力怕撞玩家扣血
const hitP1 = Math.hypot(p1.x-e.x, p1.y-e.y);
const hitP2 = Math.hypot(p2.x-e.x, p2.y-e.y);
if(hitP1<35){
p1.hp -=20; enemies.splice(i,1);
}else if(hitP2<35){
p2.hp -=20; enemies.splice(i,1);
}
}
//畫兩位玩家
ctx.fillStyle="#ff6666";
ctx.fillRect(p1.x,p1.y,p1.w,p1.h);
ctx.fillStyle="#6688ff";
ctx.fillRect(p2.x,p2.y,p2.w,p2.h);
updateUI();
}
requestAnimationFrame(gameLoop);
}
gameLoop();
window.addEventListener("resize",()=>{
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
})
</script>
</body>
</html>Game Source: 雙人數學大逃殺|苦力怕版 HTML5|可調數學難度 + 作弊功能
Creator: SparkShark50
Libraries: none
Complexity: complex (890 lines, 24.0 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: html5-sparkshark50" to link back to the original. Then publish at arcadelab.ai/publish.