🎮ArcadeLab

援救狗星人 - 狗品种武将版

by BlazingDragon43
716 lines18.9 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>援救狗星人 - 狗品种武将版</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Microsoft YaHei", sans-serif; }
  body {
    background: #000;
    color: #fff;
    overflow: hidden;
    width: 100vw;
    height: 100vh;
    user-select: none;
  }
  #game {
    position: relative;
    width: 100%;
    height: 100%;
  }

  /* 战斗场景:参考援救喵星人式插画关卡 */
  #battleScene {
    position: absolute;
    inset: 0;
    background:
      linear-gradient(180deg, #ffe9c4 0%, #ffd29a 35%, #8fbc8f 70%, #5a7a4a 100%);
    overflow: hidden;
  }
  /* 远景:城池、战旗 */
  .bg-far {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 45%;
    background:
      radial-gradient(ellipse at 30% 80%, #f7b782 0%, transparent 50%),
      radial-gradient(ellipse at 70% 70%, #ffd29a 0%, transparent 55%);
  }
  .city {
    position: absolute;
    top: 18%;
    left: 50%;
    transform: translateX(-50%);
    width: 240px;
    height: 160px;
    background:
      linear-gradient(180deg, #e8c38a 0%, #c99a55 100%);
    border: 4px solid #7a5a2a;
    border-radius: 10px 10px 0 0;
    opacity: 0.55;
  }
  .flag {
    position: absolute;
    top: 10%;
    width: 40px;
    height: 70px;
    background: #c0392b;
    border: 2px solid #7a5a2a;
  }
  /* 中景:地面纹理 */
  .bg-mid {
    position: absolute;
    top: 45%;
    left: 0;
    width: 100%;
    height: 20%;
    background:
      linear-gradient(180deg, #a5cd8c, #7fa85a);
  }
  /* 前景:战斗区 */
  .bg-ground {
    position: absolute;
    top: 60%;
    left: 0;
    width: 100%;
    height: 40%;
    background:
      linear-gradient(180deg, #8fbc8f 0%, #6f9a6a 40%, #557a45 100%);
  }
  .grass {
    position: absolute;
    top: 58%;
    width: 100%;
    height: 4%;
    background:
      repeating-linear-gradient(90deg, #a5cd8c 0 12px, #8fbc8f 12px 24px);
  }

  /* 狗将单位:完整狗形,不是人形 */
  .dog-unit {
    position: absolute;
    width: 90px;
    height: 110px;
    z-index: 10;
    transition: left 0.15s linear, bottom 0.1s;
  }
  .dog-body {
    position: relative;
    width: 100%;
    height: 100%;
  }
  /* 狗头像 */
  .dog-head {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 54px;
    height: 54px;
    border-radius: 50%;
    border: 3px solid #fff;
    background: #f4c896;
    z-index: 4;
  }
  /* 狗身体 */
  .dog-torso {
    position: absolute;
    top: 34px;
    left: 50%;
    transform: translateX(-50%);
    width: 56px;
    height: 44px;
    border-radius: 24px;
  }
  /* 狗腿 */
  .dog-leg {
    position: absolute;
    top: 70px;
    width: 14px;
    height: 34px;
    border-radius: 6px;
  }
  .dog-leg.left { left: 18px; }
  .dog-leg.right { right: 18px; }
  /* 狗尾巴 */
  .dog-tail {
    position: absolute;
    top: 40px;
    right: -10px;
    width: 30px;
    height: 10px;
    border-radius: 10px;
    transform-origin: left center;
  }
  /* 武器 */
  .dog-weapon {
    position: absolute;
    top: 30px;
    right: -14px;
    width: 10px;
    height: 50px;
    background: linear-gradient(180deg, #eee, #888);
    border: 1px solid #333;
    z-index: 3;
  }
  /* 阴影 */
  .dog-shadow {
    position: absolute;
    bottom: -6px;
    left: 50%;
    width: 70%;
    height: 10px;
    background: rgba(0,0,0,0.35);
    border-radius: 50%;
    transform: translateX(-50%);
  }
  /* 血条 */
  .hp-bar {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    width: 80px;
    height: 8px;
    background: #222;
    border: 1px solid #fff;
    border-radius: 4px;
    overflow: hidden;
    z-index: 5;
  }
  .hp-inner {
    height: 100%;
    background: linear-gradient(90deg, #4caf50, #8bc34a);
    transition: width 0.25s;
  }
  .hp-inner.enemy { background: linear-gradient(90deg, #f44336, #ff7961); }

  /* 狗将动作 */
  @keyframes dogRun {
    0%,100% { transform: translateY(0) rotate(-2deg); }
    50% { transform: translateY(-5px) rotate(2deg); }
  }
  @keyframes dogAttack {
    0% { transform: translateX(0) rotate(0); }
    40% { transform: translateX(24px) rotate(7deg); }
    100% { transform: translateX(0) rotate(0); }
  }
  @keyframes dogHit {
    0%,100% { filter: brightness(1); }
    50% { filter: brightness(2.2) saturate(0); }
  }
  @keyframes dogDie {
    0% { transform: rotate(0); opacity: 1; }
    100% { transform: rotate(80deg) translateY(20px); opacity: 0.4; }
  }
  .dog-unit.run .dog-body { animation: dogRun 0.32s infinite ease-in-out; }
  .dog-unit.atk .dog-body { animation: dogAttack 0.45s ease-out; }
  .dog-unit.hit .dog-body { animation: dogHit 0.25s; }
  .dog-unit.dead .dog-body { animation: dogDie 0.6s forwards; }

  /* 技能特效 */
  .fx {
    position: absolute;
    pointer-events: none;
    z-index: 20;
  }
  .slash-fx {
    width: 140px;
    height: 90px;
    background: radial-gradient(circle, #fff 0%, #ffd700 40%, transparent 70%);
    border-radius: 50%;
    animation: slash 0.45s forwards;
  }
  @keyframes slash {
    0% { transform: scale(0.2) rotate(-30deg); opacity: 1; }
    100% { transform: scale(1.6) rotate(35deg); opacity: 0; }
  }
  .lightning-fx {
    width: 80px;
    height: 140px;
    background: linear-gradient(180deg, #fff, #64b5f6, #1976d2);
    clip-path: polygon(40% 0, 60% 0, 50% 40, 70% 40, 30% 100, 50% 60, 20% 60);
    animation: lightning 0.4s forwards;
  }
  @keyframes lightning {
    0%,100% { opacity: 0; }
    20%,80% { opacity: 1; }
  }
  .wave-fx {
    width: 180px;
    height: 50px;
    border: 5px solid #ffeb3b;
    border-radius: 50%;
    animation: wave 0.6s forwards;
  }
  @keyframes wave {
    0% { transform: scale(0.15); opacity: 1; }
    100% { transform: scale(1.8); opacity: 0; }
  }
  .combo-fx {
    width: 100px;
    height: 80px;
    background: radial-gradient(circle, #ff5722 0%, #ffd700 50%, transparent 70%);
    border-radius: 50%;
    animation: combo 0.3s forwards;
  }
  @keyframes combo {
    0% { transform: scale(0.3); opacity: 1; }
    100% { transform: scale(1.3); opacity: 0; }
  }

  /* 伤害飘字 */
  .dmg {
    position: absolute;
    font-size: 24px;
    font-weight: bold;
    color: #ff4444;
    text-shadow: 2px 2px 0 #000;
    animation: floatUp 0.9s forwards;
    z-index: 25;
  }
  .dmg.crit {
    font-size: 32px;
    color: #ffd700;
  }
  @keyframes floatUp {
    0% { transform: translateY(0); opacity: 1; }
    100% { transform: translateY(-70px); opacity: 0; }
  }

  /* UI */
  #ui {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 30;
  }
  .btn {
    pointer-events: auto;
    background: linear-gradient(180deg, #ff9800, #e65100);
    color: #fff;
    border: none;
    padding: 10px 18px;
    border-radius: 20px;
    font-size: 14px;
    box-shadow: 0 4px 10px #0006;
  }
  #autoBtn {
    position: absolute;
    top: 10px;
    right: 10px;
  }
  #backBtn {
    position: absolute;
    top: 10px;
    left: 10px;
  }
  #result {
    position: absolute;
    top: 40%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: #000c;
    padding: 20px 40px;
    border-radius: 16px;
    font-size: 24px;
    display: none;
  }
  #result.show { display: block; }

  /* 主城 */
  #home {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, #2c3e50, #1a252f);
    padding: 20px;
    display: none;
    z-index: 40;
  }
  #home.show { display: block; }
  .menu {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
    margin-top: 20px;
  }
  .menu-item {
    background: linear-gradient(135deg, #34495e, #2c3e50);
    padding: 20px;
    border-radius: 14px;
    text-align: center;
    border: 2px solid #5d6d7e;
  }
</style>
</head>
<body>
<div id="game">
  <!-- 战斗场景 -->
  <div id="battleScene">
    <div class="bg-far">
      <div class="city"></div>
      <div class="flag" style="left:20%"></div>
      <div class="flag" style="left:75%"></div>
    </div>
    <div class="bg-mid"></div>
    <div class="grass"></div>
    <div class="bg-ground"></div>

    <button class="btn" id="backBtn" onclick="backHome()">返回主城</button>
    <button class="btn" id="autoBtn" onclick="toggleAuto()">自动:开</button>
    <div id="result">
      <div id="resultText"></div>
      <button class="btn" style="margin-top:12px" onclick="nextStage()">下一关</button>
    </div>
  </div>

  <!-- 主界面 -->
  <div id="home" class="show">
    <h1 style="color:#ffd700;text-align:center">援救狗星人 - 狗品种武将版</h1>
    <div class="menu">
      <div class="menu-item" onclick="goBattle()">⚔️ 闯关战斗</div>
      <div class="menu-item" onclick="alert('武将系统开发中')">🐶 我的狗将</div>
      <div class="menu-item" onclick="alert('招募开发中')">🎲 招募</div>
      <div class="menu-item" onclick="alert('商店开发中')">🛒 商店</div>
      <div class="menu-item" onclick="alert('任务开发中')">📜 任务</div>
      <div class="menu-item" onclick="alert('仙岛爬塔开发中')">🏔️ 仙岛爬塔</div>
    </div>
  </div>
</div>

<script>
  // ========== 狗品种武将:每个武将对应不同狗形态 ==========
  const HERO_DATA = [
    {
      id: "guanyu", name: "关羽犬", breed: "藏獒", rarity: "SSR",
      headColor: "#8b4513", torsoColor: "#2e7d32", legColor: "#1b5e20",
      tailColor: "#8b4513", weaponColor: "#bdbdbd", weaponType: "blade",
      hp: 1400, atk: 190, def: 40,
      skill: { name: "偃月斩", type: "slash", dmg: 3.0 }
    },
    {
      id: "lubu", name: "吕布拉多", breed: "杜宾", rarity: "SSR",
      headColor: "#2c2c2c", torsoColor: "#7b1fa2", legColor: "#4a148c",
      tailColor: "#2c2c2c", weaponColor: "#9e9e9e", weaponType: "dual-blade",
      hp: 1300, atk: 230, def: 38,
      skill: { name: "无双乱舞", type: "combo", dmg: 3.2 }
    },
    {
      id: "zhugeliang", name: "诸葛柴犬", breed: "柴犬", rarity: "SSR",
      headColor: "#f4c896", torsoColor: "#1565c0", legColor: "#0d47a1",
      tailColor: "#f4c896", weaponColor: "#64b5f6", weaponType: "fan",
      hp: 1000, atk: 175, def: 30,
      skill: { name: "天雷", type: "lightning", dmg: 2.8 }
    },
    {
      id: "zhangfei", name: "张飞恶霸", breed: "恶霸犬", rarity: "SSR",
      headColor: "#d4a373", torsoColor: "#e64a19", legColor: "#bf360c",
      tailColor: "#d4a373", weaponColor: "#757575", weaponType: "hammer",
      hp: 1250, atk: 210, def: 35,
      skill: { name: "咆哮震地", type: "wave", dmg: 2.6 }
    }
  ];

  // ========== 游戏状态 ==========
  let state = {
    gold: 5000,
    stage: 1,
    maxStage: 1,
    heroes: [
      { ...HERO_DATA[0], level: 1 },
      { ...HERO_DATA[1], level: 1 }
    ],
    team: [0, 1],
    auto: true,
    battle: null
  };

  // ========== 工具函数 ==========
  function $(id) { return document.getElementById(id); }
  function save() { localStorage.setItem("dogStarSave", JSON.stringify(state)); }
  function load() {
    const s = localStorage.getItem("dogStarSave");
    if (s) state = { ...state, ...JSON.parse(s) };
  }

  // ========== 主界面 ==========
  function showHome() {
    $("home").classList.add("show");
    $("battleScene").style.display = "none";
  }
  function hideHome() {
    $("home").classList.remove("show");
    $("battleScene").style.display = "block";
  }

  // ========== 创建狗将单位 ==========
  function createDogUnit(u, isEnemy) {
    const el = document.createElement("div");
    el.className = "dog-unit";
    el.id = u.uid;
    el.style.left = u.x + "px";
    el.style.bottom = u.y + "px";

    if (isEnemy) {
      el.style.transform = "scaleX(-1)";
    }

    el.innerHTML = `
      <div class="dog-body">
        <div class="hp-bar"><div class="hp-inner ${isEnemy?'enemy':''}" style="width:100%"></div></div>
        <div class="dog-head" style="background:${u.headColor}"></div>
        <div class="dog-torso" style="background:${u.torsoColor}"></div>
        <div class="dog-leg left" style="background:${u.legColor}"></div>
        <div class="dog-leg right" style="background:${u.legColor}"></div>
        <div class="dog-tail" style="background:${u.tailColor}"></div>
        <div class="dog-weapon" style="background:${u.weaponColor}"></div>
        <div class="dog-shadow"></div>
      </div>
    `;

    $("battleScene").appendChild(el);
    return el;
  }

  // ========== 战斗系统 ==========
  function startBattle() {
    hideHome();
    $("result").classList.remove("show");

    document.querySelectorAll(".dog-unit, .fx").forEach(el => el.remove());

    const selfTeam = state.team.map(i => state.heroes[i]).filter(Boolean);
    const enemyTeam = [
      { id: "e1", name: "小兵", breed: "土狗", headColor: "#d7ccc8", torsoColor: "#6d4c41", legColor: "#4e342e", tailColor: "#d7ccc8", weaponColor: "#9e9e9e", hp: 600, atk: 70, def: 10, skill: { type: "slash" } },
      { id: "e2", name: "小兵", breed: "土狗", headColor: "#d7ccc8", torsoColor: "#6d4c41", legColor: "#4e342e", tailColor: "#d7ccc8", weaponColor: "#9e9e9e", hp: 600, atk: 70, def: 10, skill: { type: "slash" } },
      { id: "e3", name: "小兵", breed: "土狗", headColor: "#d7ccc8", torsoColor: "#6d4c41", legColor: "#4e342e", tailColor: "#d7ccc8", weaponColor: "#9e9e9e", hp: 600, atk: 70, def: 10, skill: { type: "slash" } }
    ];

    state.battle = {
      self: selfTeam.map((h, i) => ({
        ...h,
        uid: "s" + i,
        x: 60 + i * 50,
        y: 60 + (i % 2) * 25,
        nowHp: h.hp,
        maxHp: h.hp,
        target: null,
        cd: 0,
        state: "run"
      })),
      enemy: enemyTeam.map((h, i) => ({
        ...h,
        uid: "e" + i,
        x: window.innerWidth - 100 - i * 50,
        y: 60 + (i % 2) * 25,
        nowHp: h.hp,
        maxHp: h.hp,
        target: null,
        cd: 0,
        state: "run"
      })),
      time: 0,
      over: false
    };

    state.battle.self.forEach(u => createDogUnit(u, false));
    state.battle.enemy.forEach(u => createDogUnit(u, true));

    battleLoop();
  }

  function battleLoop() {
    if (state.battle.over) return;
    state.battle.time++;

    const b = state.battle;

    // 选目标
    b.self.forEach(u => {
      if (!u.target || u.target.nowHp <= 0) u.target = b.enemy.find(e => e.nowHp > 0);
    });
    b.enemy.forEach(u => {
      if (!u.target || u.target.nowHp <= 0) u.target = b.self.find(e => e.nowHp > 0);
    });

    // 我方狗将冲向敌人
    b.self.forEach(u => {
      if (!u.target || u.nowHp <= 0) return;
      const dx = u.target.x - u.x;
      const dist = Math.abs(dx);

      if (dist > 110) {
        u.x += Math.sign(dx) * 1.6;
        u.state = "run";
        const el = $(u.uid);
        if (el) {
          el.style.left = u.x + "px";
          el.classList.remove("atk", "hit");
          el.classList.add("run");
        }
      } else {
        u.state = "idle";
        const el = $(u.uid);
        if (el) el.classList.remove("run");

        u.cd--;
        if (u.cd <= 0) {
          u.cd = 60;
          dogAttack(u, u.target);
        }
      }
    });

    // 敌方狗将冲向我方
    b.enemy.forEach(u => {
      if (!u.target || u.nowHp <= 0) return;
      const dx = u.target.x - u.x;
      const dist = Math.abs(dx);

      if (dist > 110) {
        u.x += Math.sign(dx) * 1.3;
        u.state = "run";
        const el = $(u.uid);
        if (el) {
          el.style.left = u.x + "px";
          el.classList.remove("atk", "hit");
          el.classList.add("run");
        }
      } else {
        u.state = "idle";
        const el = $(u.uid);
        if (el) el.classList.remove("run");

        u.cd--;
        if (u.cd <= 0) {
          u.cd = 70;
          dogAttack(u, u.target);
        }
      }
    });

    // 胜负判定
    if (b.self.every(u => u.nowHp <= 0)) return endBattle(false);
    if (b.enemy.every(u => u.nowHp <= 0)) return endBattle(true);

    requestAnimationFrame(battleLoop);
  }

  // 狗将攻击
  function dogAttack(attacker, target) {
    const aEl = $(attacker.uid);
    const tEl = $(target.uid);
    if (!aEl || !tEl) return;

    aEl.classList.remove("run");
    aEl.classList.add("atk");
    setTimeout(() => aEl.classList.remove("atk"), 450);

    setTimeout(() => {
      const dmg = Math.max(1, attacker.atk - target.def + Math.floor(Math.random() * 20));
      target.nowHp -= dmg;
      showDmg(target, dmg, false);
      tEl.classList.add("hit");
      setTimeout(() => tEl.classList.remove("hit"), 250);
      updateHp(target);

      if (Math.random() < 0.3) {
        useSkill(attacker, target);
      }
    }, 280);
  }

  // 狗将技能
  function useSkill(attacker, target) {
    const aEl = $(attacker.uid);
    const tEl = $(target.uid);
    if (!aEl || !tEl) return;

    aEl.classList.add("atk");
    setTimeout(() => aEl.classList.remove("atk"), 450);

    const dmg = Math.floor(attacker.atk * attacker.skill.dmg);
    target.nowHp -= dmg;
    showDmg(target, dmg, true);
    tEl.classList.add("hit");
    setTimeout(() => tEl.classList.remove("hit"), 250);
    updateHp(target);

    if (attacker.skill.type === "slash") {
      createFx(target, "slash-fx");
    } else if (attacker.skill.type === "lightning") {
      createFx(target, "lightning-fx");
    } else if (attacker.skill.type === "wave") {
      createFx(target, "wave-fx");
    } else if (attacker.skill.type === "combo") {
      for (let i = 0; i < 3; i++) {
        setTimeout(() => createFx(target, "combo-fx"), i * 140);
      }
    }
  }

  function createFx(target, type) {
    const fx = document.createElement("div");
    fx.className = "fx " + type;
    fx.style.left = target.x + 20 + "px";
    fx.style.bottom = target.y + 40 + "px";
    $("battleScene").appendChild(fx);
    setTimeout(() => fx.remove(), 600);
  }

  function showDmg(target, val, crit) {
    const d = document.createElement("div");
    d.className = "dmg" + (crit ? " crit" : "");
    d.innerText = "-" + val;
    d.style.left = target.x + 24 + "px";
    d.style.bottom = target.y + 80 + "px";
    $("battleScene").appendChild(d);
    setTimeout(() => d.remove(), 900);
  }

  function updateHp(u) {
    const el = $(u.uid);
    if (!el) return;
    const bar = el.querySelector(".hp-inner");
    if (bar) bar.style.width = Math.max(0, u.nowHp / u.maxHp * 100) + "%";
  }

  function endBattle(win) {
    state.battle.over = true;
    $("result").classList.add("show");
    if (win) {
      $("resultText").innerText = "胜利!";
      state.gold += 500;
      state.maxStage = Math.max(state.maxStage, state.stage);
    } else {
      $("resultText").innerText = "战败";
    }
    save();
  }

  function nextStage() {
    state.stage++;
    startBattle();
  }

  function goBattle() {
    startBattle();
  }
  function backHome() {
    if (state.battle) state.battle.over = true;
    showHome();
  }
  function toggleAuto() {
    state.auto = !state.auto;
    $("autoBtn").innerText = "自动:" + (state.auto ? "开" : "关");
  }

  // ========== 初始化 ==========
  load();
  showHome();
</script>
</body>
</html>

Game Source: 援救狗星人 - 狗品种武将版

Creator: BlazingDragon43

Libraries: none

Complexity: complex (716 lines, 18.9 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-blazingdragon43" to link back to the original. Then publish at arcadelab.ai/publish.