援救狗星人 - 狗品种武将版
by BlazingDragon43716 lines18.9 KB
<!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.