🎮ArcadeLab

方塊RPG冒險

by SparkShark50
594 lines19.5 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-HK">
<head>
<meta charset="UTF-8">
<title>方塊RPG冒險</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;font-family:system-ui, sans-serif}
body{background:#222;color:#fff;overflow:hidden}

/* 主頁 */
#主頁{width:100vw;height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:24px}
#主頁 h1{font-size:24px}
#開始按鈕{padding:14px 32px;font-size:17px;background:#444;border:2px solid #777;border-radius:4px;cursor:pointer;transition:background 0.2s}
#開始按鈕:hover{background:#555}

/* 難度頁 */
#難度頁{width:100vw;height:100vh;display:none;flex-direction:column;align-items:center;justify-content:center;gap:20px}
#難度頁 h2{font-size:20px}
.難度掣{width:120px;padding:10px;font-size:15px;margin:5px;background:#333;border:2px solid #666;border-radius:4px;cursor:pointer;transition:0.2s}
.難度掣:hover{background:#505050}

/* 戰鬥頁 */
#戰鬥頁{width:100vw;height:100vh;display:none;position:relative}
.左上資訊{position:absolute;top:12px;left:12px;font-size:14px;line-height:1.4}
.右側功能欄{position:absolute;top:12px;right:12px;display:flex;flex-direction:column;gap:6px}
.功能掣{padding:6px 10px;background:#333;border:1px solid #888;border-radius:3px;cursor:pointer;font-size:13px}
.中間戰鬥區{position:absolute;top:48%;left:50%;transform:translate(-50%,-50%);text-align:center;width:80%}
#怪物圖{width:110px;height:110px;object-fit:contain;cursor:pointer;transition:0.15s;user-select:none}
#怪物圖:active{transform:scale(0.95)}
.血量行{font-size:14px;margin:6px 0}
#怪血量{color:#ff6666}
#我血量{color:#66ff66}
#吸收血量{color:#ffdd44}
#倒數提示{color:#ffaa00;font-size:15px;height:20px;margin:5px 0}
.應對按鈕{margin:5px;padding:7px 12px;font-size:14px;cursor:pointer;display:none}

/* 攻擊冷卻 */
#攻擊冷卻容器{width:220px;height:5px;background:#444;margin:7px auto;border-radius:2px}
#攻擊冷卻條{height:100%;background:#77dd77;width:100%;transition:width 0.05s linear}

/* 彈窗通用 */
.彈窗{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#333;border:2px solid #aaa;padding:16px;display:none;z-index:99;width:360px;max-height:80vh;overflow-y:auto}
.彈窗 h3{margin-bottom:10px;font-size:17px}
.彈窗 p,.彈窗 label{font-size:13px;margin-bottom:6px}
.彈窗掣{margin:4px 3px 0 0;padding:6px 10px;font-size:13px;cursor:pointer}

/* 商店 */
.商店分類欄{display:flex;gap:4px;margin-bottom:10px;flex-wrap:wrap}
.分類標籤{padding:5px 9px;font-size:12px;background:#444;cursor:pointer;border-radius:2px}
.分類標籤.揀中{background:#668}
.物品格{padding:6px;margin:4px 0;background:#3a3a3a;border-radius:3px;font-size:13px}
.物品格 button{margin-left:6px;padding:3px 7px;font-size:12px}

/* 背包 */
.背包物品欄{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.背包物品{padding:6px 10px;background:#444;border-radius:3px;font-size:12px;cursor:pointer;display:flex;flex-direction:column;gap:4px;min-width:90px}
.背包物品 button{font-size:12px;padding:3px 6px}

/* 礦場項目 + 獨立挖礦冷卻條 */
.mine-item{padding:8px;margin:6px 0;background:#3a3a3a;border-radius:3px;font-size:13px}
.mine-cooldown-wrap{width:100%;height:4px;background:#222;margin-top:4px;border-radius:2px}
.mine-cooldown-bar{height:100%;background:#6cf;width:100%;transition:width 0.05s linear}
</style>
</head>
<body>

<!-- 主頁 -->
<div id="主頁">
  <h1>方塊RPG冒險</h1>
  <div id="開始按鈕">開始遊戲</div>
</div>

<!-- 難度頁 -->
<div id="難度頁">
  <h2>選擇難度</h2>
  <div class="難度掣" data-d="簡單">簡單</div>
  <div class="難度掣" data-d="中等">中等</div>
  <div class="難度掣" data-d="困難">困難</div>
</div>

<!-- 戰鬥頁 -->
<div id="戰鬥頁">
  <div class="左上資訊">
    金幣:<span id="金幣">0</span><br>
    挖礦次數:<span id="挖礦次數">50</span>
  </div>
  <div class="右側功能欄">
    <button class="功能掣" onclick="開設定()">設定</button>
    <button class="功能掣" onclick="開商店()">商店</button>
    <button class="功能掣" onclick="開背包()">背包</button>
    <button class="功能掣" onclick="開礦場()">礦場</button>
  </div>

  <div class="中間戰鬥區">
    <img id="怪物圖" alt="怪物">
    <div id="倒數提示"></div>
    <div class="血量行">怪物血量:<span id="怪血量">30 / 30</span></div>
    <div class="血量行">我方血量:<span id="我血量">50 / <span id="最大血">50</span></span></div>
    <div class="血量行" id="吸收行" style="display:none">吸收血量:<span id="吸收血量">0</span></div>
    <div id="攻擊冷卻容器"><div id="攻擊冷卻條"></div></div>
    <button class="應對按鈕" id="後退掣" onclick="後退()">後退</button>
  </div>
</div>

<!-- 設定彈窗 -->
<div class="彈窗" id="設定彈窗">
  <h3>設定</h3>
  <button class="彈窗掣" onclick="重新開始()">重新開始遊戲</button>
  <button class="彈窗掣" onclick="關彈窗('設定彈窗')">關閉</button>
</div>

<!-- 商店彈窗 -->
<div class="彈窗" id="商店彈窗">
  <h3>商店</h3>
  <div class="商店分類欄">
    <div class="分類標籤" data-cat="weapon">武器</div>
    <div class="分類標籤" data-cat="enchant">附魔簿</div>
    <div class="分類標籤" data-cat="food">食物</div>
    <div class="分類標籤" data-cat="bow">弓箭</div>
    <div class="分類標籤" data-cat="armor">護甲</div>
    <div class="分類標籤" data-cat="block">方塊</div>
  </div>
  <div id="商店物品區"></div>
  <button class="彈窗掣" onclick="關彈窗('商店彈窗')">關閉</button>
</div>

<!-- 背包彈窗 -->
<div class="彈窗" id="背包彈窗">
  <h3>背包</h3>
  <div id="背包物品欄" class="背包物品欄"></div>
  <button class="彈窗掣" onclick="關彈窗('背包彈窗')">關閉</button>
</div>

<!-- 礦場彈窗 -->
<div class="彈窗" id="礦場彈窗">
  <h3>礦場</h3>
  <div id="礦場物品區"></div>
  <button class="彈窗掣" onclick="關彈窗('礦場彈窗')">關閉</button>
</div>

<script>
// 元素
const 主頁 = document.getElementById('主頁');
const 難度頁 = document.getElementById('難度頁');
const 戰鬥頁 = document.getElementById('戰鬥頁');
const 開始按鈕 = document.getElementById('開始按鈕');
const 怪物圖 = document.getElementById('怪物圖');
const 怪血量文字 = document.getElementById('怪血量');
const 我血量文字 = document.getElementById('我血量');
const 最大血文字 = document.getElementById('最大血');
const 金幣文字 = document.getElementById('金幣');
const 挖礦次數文字 = document.getElementById('挖礦次數');
const 倒數提示 = document.getElementById('倒數提示');
const 後退掣 = document.getElementById('後退掣');
const 攻擊冷卻條 = document.getElementById('攻擊冷卻條');
const 吸收行 = document.getElementById('吸收行');
const 吸收血量文字 = document.getElementById('吸收血量');

// 怪物列表:只保留殭屍、苦力怕
const 怪物列表 = [
  {
    名稱:"殭屍",
    圖:"",
    血量:30
  },
  {
    名稱:"苦力怕",
    圖:"",
    血量:10,
    係苦力怕:true
  }
];

// 商店物品
const 商店物品 = {
  weapon:[
    {name:"木劍",price:10,type:"weapon",durability:20,damage:7},
    {name:"鐵劍",price:30,type:"weapon",durability:30,damage:12},
    {name:"鑽石劍",price:80,type:"weapon",durability:40,damage:18}
  ],
  enchant:[
    {name:"附魔簿Ⅰ",price:15,type:"enchant",level:1},
    {name:"附魔簿Ⅱ",price:30,type:"enchant",level:2},
    {name:"附魔簿Ⅲ",price:50,type:"enchant",level:3},
    {name:"附魔簿Ⅳ",price:75,type:"enchant",level:4},
    {name:"鋒利Ⅰ",price:20,type:"sharp",level:1},
    {name:"鋒利Ⅱ",price:40,type:"sharp",level:2},
    {name:"鋒利Ⅲ",price:60,type:"sharp",level:3},
    {name:"鋒利Ⅳ",price:85,type:"sharp",level:4},
    {name:"鋒利Ⅴ",price:110,type:"sharp",level:5}
  ],
  food:[
    {name:"麵包",price:8,type:"food",heal:15},
    {name:"牛排",price:16,type:"food",heal:30},
    {name:"金蘋果",price:40,type:"goldenApple",absorb:20,duration:30000}
  ],
  bow:[
    {name:"普通弓",price:25,type:"bow",durability:25,dmg:9},
    {name:"強化弓",price:60,type:"bow",durability:35,dmg:16},
    {name:"普通箭",price:3,type:"arrow"},
    {name:"火焰箭",price:12,type:"fireArrow"}
  ],
  armor:[
    {name:"皮甲",price:25,type:"armor",maxHpAdd:10,blockTimes:5},
    {name:"鐵甲",price:60,type:"armor",maxHpAdd:15,blockTimes:10},
    {name:"鑽石甲",price:120,type:"armor",maxHpAdd:20,blockTimes:20}
  ],
  block:[
    {name:"羊毛",price:12,type:"wool"},
    {name:"石頭",price:18,type:"stoneBlock"}
  ]
};

// 礦場設定
const 礦場列表 = [
  {name:"石頭",unlockCost:0,reward:1},
  {name:"煤炭",unlockCost:20,reward:3},
  {name:"鐵礦",unlockCost:50,reward:5},
  {name:"鑽石礦",unlockCost:100,reward:20}
];

// 遊戲變數
let 基礎最大血 = 50;
let 玩家血 = 50;
let 吸收血量 = 0;
let 吸收計時器 = null;
let 金幣 = 0;
let 挖礦次數 = 50;
let 已解鎖礦 = [true,false,false,false];
let 背包 = [];
let 當前怪物序號 = 0;
let 怪物最大血 = 30;
let 怪物血 = 30;
let 爆炸計時器 = null;
let 緊急狀態 = false;
let 攻擊冷卻中 = false;
let 攻擊冷卻時間 = 800;
let 挖礦冷卻時間 = 500;
let 打中次數 = 0;
let 裝備護甲 = null;
let 礦冷卻狀態 = [false,false,false,false];

function getMaxHp(){
  let add = 0;
  if(裝備護甲) add += 裝備護甲.maxHpAdd;
  return 基礎最大血 + add;
}

function 更新畫面(){
  const maxHp = getMaxHp();
  怪血量文字.textContent = `${怪物血} / ${怪物最大血}`;
  我血量文字.textContent = `${玩家血} / `;
  最大血文字.textContent = maxHp;
  金幣文字.textContent = 金幣;
  挖礦次數文字.textContent = 挖礦次數;
  if(吸收血量 > 0){
    吸收行.style.display = "block";
    吸收血量文字.textContent = 吸收血量;
  }else{
    吸收行.style.display = "none";
  }
}

function 載入怪物(序號){
  const m = 怪物列表[序號];
  怪物圖.src = m.圖;
  怪物圖.alt = m.名稱;
  怪物最大血 = m.血量;
  怪物血 = 怪物最大血;
  緊急狀態 = false;
  倒數提示.textContent = "";
  後退掣.style.display = "none";
  更新畫面();
}

// 開始按鈕
開始按鈕.onclick = ()=>{
  主頁.style.display = 'none';
  難度頁.style.display = 'flex';
}

// 揀難度
document.querySelectorAll('.難度掣').forEach(btn=>{
  btn.onclick = ()=>{
    const d = btn.dataset.d;
    if(d === '簡單') window.怪攻擊 = 4;
    else if(d === '中等') window.怪攻擊 = 7;
    else window.怪攻擊 = 10;
    玩家血 = getMaxHp();
    當前怪物序號 = 0;
    打中次數 = 0;
    載入怪物(當前怪物序號);
    難度頁.style.display = 'none';
    戰鬥頁.style.display = 'block';
  }
})

// 攻擊怪物
怪物圖.onclick = async ()=>{
  if(緊急狀態 || 攻擊冷卻中) return;
  攻擊冷卻中 = true;
  let t = 攻擊冷卻時間;
  攻擊冷卻條.style.width = "0%";
  const step = 40;
  while(t>0){
    await sleep(step);
    t -= step;
    攻擊冷卻條.style.width = ((攻擊冷卻時間 - t)/攻擊冷卻時間 *100)+"%";
  }
  攻擊冷卻條.style.width = "100%";
  攻擊冷卻中 = false;

  const 劍 = 背包.find(x=>x.type==="weapon");
  let dmg = 7;
  if(劍 && 劍.durability>0){
    dmg = 劍.damage;
    劍.durability--;
    if(劍.durability <= 0){
      alert(`${劍.name}已損毀`);
      const i = 背包.indexOf(劍);
      if(i>-1)背包.splice(i,1);
    }
  }
  怪物血 -= dmg;
  打中次數 ++;
  if(打中次數 %5 === 0){
    挖礦次數 +=1;
    alert("累計命中5次,挖礦次數+1");
  }

  if(怪物血 <= 0){
    怪物血 = 0;
    更新畫面();
    挖礦次數 +=3;
    alert("擊敗目標,挖礦次數+3");
    打中次數 = 0;
    if(當前怪物序號 < 怪物列表.length -1){
      當前怪物序號++;
      載入怪物(當前怪物序號);
    }else{
      alert("已擊敗全部怪物!");
    }
    return;
  }

  // 怪物反擊
  let hitDmg = window.怪攻擊;
  if(裝備護甲 && 裝備護甲.blockTimes>0){
    裝備護甲.blockTimes--;
    hitDmg = Math.floor(hitDmg/2);
    if(裝備護甲.blockTimes <=0){
      alert(`${裝備護甲.name}已損毀`);
      const i = 背包.indexOf(裝備護甲);
      if(i>-1)背包.splice(i,1);
      裝備護甲 = null;
    }
  }
  if(吸收血量>0){
    const sub = Math.min(吸收血量, hitDmg);
    吸收血量 -= sub;
    hitDmg -= sub;
  }
  玩家血 -= hitDmg;
  if(玩家血 <=0){
    玩家血 = 0;
    更新畫面();
    alert('你被擊敗,遊戲結束');
    return;
  }
  更新畫面();

  if(怪物列表[當前怪物序號].係苦力怕){
    緊急狀態 = true;
    倒數提示.textContent = "苦力怕爆炸倒數 3 秒";
    後退掣.style.display = "inline-block";
    let sec =3;
    爆炸計時器 = setInterval(()=>{
      sec--;
      倒數提示.textContent = `苦力怕爆炸倒數 ${sec} 秒`;
      if(sec <=0){
        clearInterval(爆炸計時器);
        let bombDmg =50;
        if(吸收血量>0){
          const sub = Math.min(吸收血量,bombDmg);
          吸收血量 -= sub;
          bombDmg -= sub;
        }
        玩家血 -= bombDmg;
        alert(`苦力怕爆炸,未進行應對,受到50點傷害`);
        if(玩家血 <=0){
          玩家血=0;
          更新畫面();
          alert('你被擊敗');
        }else{
          緊急狀態=false;
          倒數提示.textContent="";
          後退掣.style.display="none";
        }
        更新畫面();
      }
    },1000);
  }
}

function 後退(){
  if(!緊急狀態) return;
  clearInterval(爆炸計時器);
  緊急狀態 = false;
  let dmg =30;
  if(吸收血量>0){
    const sub = Math.min(吸收血量,dmg);
    吸收血量 -= sub;
    dmg -= sub;
  }
  玩家血 -= dmg;
  倒數提示.textContent = "執行後退,受到30點傷害";
  後退掣.style.display = "none";
  更新畫面();
  if(玩家血 <=0){
    alert('你被擊敗');
  }
}

// 彈窗
function 關彈窗(id){document.getElementById(id).style.display='none'}
function 開設定(){document.getElementById('設定彈窗').style.display='block'}
function 開商店(){
  document.getElementById('商店彈窗').style.display='block';
  renderShop("weapon");
}
function 開背包(){
  document.getElementById('背包彈窗').style.display='block';
  renderBag();
}
function 開礦場(){
  document.getElementById('礦場彈窗').style.display='block';
  renderMine();
}

// 渲染商店
let nowShopCat = "weapon";
document.querySelectorAll('.分類標籤').forEach(t=>{
  t.onclick = ()=>{
    document.querySelectorAll('.分類標籤').forEach(x=>x.classList.remove('揀中'));
    t.classList.add('揀中');
    nowShopCat = t.dataset.cat;
    renderShop(nowShopCat);
  }
})
function renderShop(cat){
  const box = document.getElementById("商店物品區");
  box.innerHTML = "";
  const list = 商店物品[cat];
  list.forEach(it=>{
    const div = document.createElement("div");
    div.className="物品格";
    div.innerHTML = `${it.name} - ${it.price}金幣 <button>購買</button>`;
    div.querySelector("button").onclick = ()=>{
      if(金幣 >= it.price){
        金幣 -= it.price;
        背包.push({...it});
        更新畫面();
        alert(`購入${it.name}`);
      }else alert("金幣不足");
    }
    box.appendChild(div);
  })
}

// 渲染背包:直接按使用,唔使手持
function renderBag(){
  const box = document.getElementById("背包物品欄");
  box.innerHTML = "";
  背包.forEach((it,i)=>{
    const div = document.createElement("div");
    div.className = "背包物品";
    div.innerHTML = `${it.name}<button>使用</button>`;
    div.querySelector("button").onclick = ()=>{
      if(it.type === "wool"){
        if(!緊急狀態){alert("當前無法放置羊毛");return;}
        clearInterval(爆炸計時器);
        緊急狀態=false;
        let dmg=10;
        if(吸收血量>0){
          const sub = Math.min(吸收血量,dmg);
          吸收血量 -= sub;
          dmg -= sub;
        }
        玩家血 -= dmg;
        背包.splice(i,1);
        倒數提示.textContent="放置羊毛阻擋爆炸,受到10點傷害";
        後退掣.style.display="none";
      }else if(it.type === "stoneBlock"){
        if(!緊急狀態){alert("當前無法放置石頭");return;}
        clearInterval(爆炸計時器);
        緊急狀態=false;
        let dmg=5;
        if(吸收血量>0){
          const sub = Math.min(吸收血量,dmg);
          吸收血量 -= sub;
          dmg -= sub;
        }
        玩家血 -= dmg;
        背包.splice(i,1);
        倒數提示.textContent="放置石頭阻擋爆炸,受到5點傷害";
        後退掣.style.display="none";
      }else if(it.type === "food"){
        玩家血 = Math.min(玩家血 + it.heal, getMaxHp());
        背包.splice(i,1);
        alert(`使用${it.name},回復${it.heal}生命值`);
      }else if(it.type === "goldenApple"){
        吸收血量 = it.absorb;
        if(吸收計時器) clearTimeout(吸收計時器);
        吸收計時器 = setTimeout(()=>{
          吸收血量=0;更新畫面();
          alert("金蘋果吸收效果結束");
        },it.duration);
        背包.splice(i,1);
        alert("使用金蘋果,30秒內獲得20點吸收血量");
      }else if(it.type === "armor"){
        裝備護甲 = it;
        alert(`裝備${it.name},生命值上限+${it.maxHpAdd},可抵擋${it.blockTimes}次攻擊`);
      }else if(it.type === "weapon" || it.type === "bow"){
        alert("武器與弓自動生效,攻擊時自動消耗耐久");
      }else{
        alert("該物品暫無法使用");
      }
      更新畫面();
      renderBag();
    }
    box.appendChild(div);
  })
}

// 渲染礦場,每個礦物獨立冷卻條
async function renderMine(){
  const box = document.getElementById("礦場物品區");
  box.innerHTML = "";
  for(let i=0;i<礦場列表.length;i++){
    const m = 礦場列表[i];
    const wrap = document.createElement("div");
    wrap.className="mine-item";
    if(!已解鎖礦[i]){
      wrap.innerHTML = `
        <div>${m.name}|解鎖費用:${m.unlockCost}金幣 <button>解鎖</button></div>
        <div class="mine-cooldown-wrap"><div class="mine-cooldown-bar" style="width:100%"></div></div>
      `;
      wrap.querySelector("button").onclick = ()=>{
        if(金幣 >= m.unlockCost){
          金幣 -= m.unlockCost;
          已解鎖礦[i]=true;
          更新畫面();
          renderMine();
        }else alert("金幣不足");
      }
    }else{
      wrap.innerHTML = `
        <div>${m.name}|每次獲得+${m.reward}金幣 <button>挖礦</button></div>
        <div class="mine-cooldown-wrap"><div class="mine-cooldown-bar" style="width:100%"></div></div>
      `;
      const bar = wrap.querySelector(".mine-cooldown-bar");
      wrap.querySelector("button").onclick = async ()=>{
        if(礦冷卻狀態[i]) return;
        if(挖礦次數 <=0){alert("挖礦次數已用盡");return;}
        礦冷卻狀態[i]=true;
        bar.style.width = "0%";
        let t = 挖礦冷卻時間;
        const step = 40;
        while(t>0){
          await sleep(step);
          t -= step;
          bar.style.width = ((挖礦冷卻時間 - t)/挖礦冷卻時間 *100)+"%";
        }
        bar.style.width = "100%";
        礦冷卻狀態[i]=false;

        挖礦次數--;
        金幣 += m.reward;
        alert(`開採${m.name},獲得${m.reward}金幣`);
        更新畫面();
        renderMine();
      }
    }
    box.appendChild(wrap);
  }
}

function sleep(ms){return new Promise(r=>setTimeout(r,ms))}

function 重新開始(){location.reload()}
更新畫面();
</script>
</body>
</html>

Game Source: 方塊RPG冒險

Creator: SparkShark50

Libraries: none

Complexity: complex (594 lines, 19.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: rpg-sparkshark50" to link back to the original. Then publish at arcadelab.ai/publish.