火焰豌豆大冒险
by MysticPanda75745 lines24.5 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>火焰豌豆大冒险</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent;}
html,body{width:100%;height:100%;overflow:hidden;background:#111;font-family:system-ui,sans-serif;}
#gameCanvas{display:block;width:100%;height:100%;background:#529c49;}
#joystickArea{position:fixed;bottom:40px;left:40px;width:140px;height:140px;background:rgba(255,255,255,0.2);border-radius:50%;touch-action:none;z-index:10;}
#joystickKnob{position:absolute;width:60px;height:60px;background:rgba(255,255,255,0.5);border-radius:50%;left:40px;top:40px;}
#fireBtn{position:fixed;bottom:40px;right:40px;width:110px;height:110px;border-radius:50%;background:#ff6622;color:white;font-size:24px;border:none;touch-action:none;z-index:10;}
#shopBtn{position:fixed;top:20px;right:20px;padding:12px 18px;font-size:20px;border-radius:10px;border:none;background:#4285f4;color:white;z-index:10;}
#shopPanel{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:380px;background:#222;padding:20px;border-radius:12px;color:white;display:none;border:2px solid #888;z-index:100;}
.shop-item{padding:10px;margin:8px 0;background:#333;border-radius:6px;display:flex;justify-content:space-between;align-items:center;}
.shop-item button{padding:6px 10px;border:none;border-radius:4px;background:#28a745;color:white;}
#closeShop{width:100%;margin-top:12px;padding:8px;background:#dc3545;border:none;color:white;border-radius:6px;font-size:16px;}
#cardPanel{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:460px;background:#1a1a1a;padding:24px;border-radius:14px;color:white;display:none;border:2px solid #ffcc00;text-align:center;z-index:100;}
.card-choice{display:inline-block;width:125px;padding:12px 8px;margin:6px;background:#333;border-radius:8px;border:1px solid #777;cursor:pointer;vertical-align:top;}
.card-choice:hover{background:#444;border-color:#ffcc00;}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="joystickArea"><div id="joystickKnob"></div></div>
<button id="fireBtn">🔥追踪弹</button>
<button id="shopBtn">🏪商店</button>
<div id="shopPanel">
<h3 style="text-align:center;margin:0 0 15px">火焰豌豆商店</h3>
<div class="shop-item"><span>❤️恢复20血量</span><button data-type="heal">20铜币</button></div>
<div class="shop-item"><span>⚡移动速度+1(永久)</span><button data-type="speed">50铜币</button></div>
<div class="shop-item"><span>🔥子弹速度+2(永久)</span><button data-type="bulletSpeed">60铜币</button></div>
<div class="shop-item"><span>💥子弹伤害+1(永久)</span><button data-type="bulletDmg">80铜币</button></div>
<div class="shop-item"><span>🔫射速提升(永久)</span><button data-type="fireRate">90铜币</button></div>
<div class="shop-item"><span>🛡️受伤冷却+1秒(永久)</span><button data-type="coolUp">100铜币</button></div>
<div class="shop-item"><span>💰击杀铜币+1(永久)</span><button data-type="coinBonus">120铜币</button></div>
<div class="shop-item"><span>💖最大血量+20(永久)</span><button data-type="maxHp">150铜币</button></div>
<div class="shop-item"><span>🤖自动射击(永久)</span><button data-type="autoFire">180铜币</button></div>
<div class="shop-item"><span>💣击杀爆炸(永久)</span><button data-type="explodeKill">200铜币</button></div>
<div class="shop-item"><span>🌱三发爆发卡牌【10秒】</span><button data-type="cardTriple">100铜币</button></div>
<div class="shop-item"><span>❄️寒冰射手卡牌</span><button data-type="cardIce">140铜币</button></div>
<div class="shop-item"><span>🪨坚果墙卡牌</span><button data-type="cardNut">160铜币</button></div>
<button id="closeShop">关闭商店</button>
</div>
<div id="cardPanel">
<h3 style="margin:0 0 16px">🎴选择一张卡牌</h3>
<div id="cardList"></div>
</div>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
function resizeCanvas(){canvas.width = window.innerWidth;canvas.height = window.innerHeight;}
resizeCanvas();
window.addEventListener("resize",resizeCanvas);
const player = {
x: canvas.width/2,
y: canvas.height/2,
size: 50,
speed: 4,
hp: 100,
maxHp:100
};
let gameOver = false;
let bulletDamage = 1;
let fireDelay = 800;
let lastFireTime = 0;
let hurtCoolAdd = 0;
let killCoinBonus = 0;
let autoFire = false;
let explodeKill = false;
let coin = 0;
let killCount = 0;
let slowZombieTimer = 0;
let doubleCoinTimer = 0;
let piercingTimer = 0;
let shieldTimer = 0;
let instantKillCount = 0;
let bombWaveTimer = 0;
let summonHelperTimer = 0;
let weakZombieTimer = 0;
let tripleShotTimer = 0; //三发buff持续10秒
let bullets = [];
let enemies = [];
let enemyHitCool = new Map();
let helper = null;
let plants = [];
let playerCards = []; //玩家背包卡牌
let boss = null;
const BOSS_KILL_REQUIRE = 50;
const joystickArea = document.getElementById("joystickArea");
const joystickKnob = document.getElementById("joystickKnob");
const fireBtn = document.getElementById("fireBtn");
const shopBtn = document.getElementById("shopBtn");
const shopPanel = document.getElementById("shopPanel");
const closeShop = document.getElementById("closeShop");
const shopButtons = document.querySelectorAll(".shop-item button");
const cardPanel = document.getElementById("cardPanel");
const cardList = document.getElementById("cardList");
let joyActive = false;
let joyDx = 0, joyDy = 0;
joystickArea.addEventListener("touchstart", e=>{
e.preventDefault();
joyActive = true;
});
joystickArea.addEventListener("touchmove", e=>{
e.preventDefault();
const rect = joystickArea.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
const touch = e.touches[0];
let x = touch.clientX - cx;
let y = touch.clientY - cy;
const dist = Math.hypot(x, y);
if(dist > 60){
x = x / dist * 60;
y = y / dist * 60;
}
joyDx = x / 60;
joyDy = y / 60;
joystickKnob.style.left = (40 + x) + "px";
joystickKnob.style.top = (40 + y) + "px";
});
joystickArea.addEventListener("touchend", ()=>{
joyActive = false;
joyDx = 0;
joyDy = 0;
joystickKnob.style.left = "40px";
joystickKnob.style.top = "40px";
});
function shoot(){
if(gameOver) return;
if(shopPanel.style.display === "block" || cardPanel.style.display === "block") return;
const now = Date.now();
if(now - lastFireTime < fireDelay) return;
if(enemies.length === 0) return;
lastFireTime = now;
let nearest = enemies[0];
let minD = Math.hypot(nearest.x - player.x, nearest.y - player.y);
for(let e of enemies){
let d = Math.hypot(e.x - player.x, e.y - player.y);
if(d < minD){
minD = d;
nearest = e;
}
}
//基础子弹
bullets.push({
x: player.x,
y: player.y,
target: nearest,
speed: 9,
size: 14,
damage: bulletDamage,
pierce: piercingTimer > 0,
fromPlant: false
});
//三发buff生效:额外多发2颗,总共3发!持续10秒
if(tripleShotTimer > 0){
bullets.push({
x: player.x,
y: player.y,
target: nearest,
speed: 9,
size: 14,
damage: bulletDamage,
pierce: piercingTimer > 0,
fromPlant: false,
angleOffset:-0.12
});
bullets.push({
x: player.x,
y: player.y,
target: nearest,
speed: 9,
size: 14,
damage: bulletDamage,
pierce: piercingTimer > 0,
fromPlant: false,
angleOffset:0.12
});
}
}
fireBtn.addEventListener("touchstart", e=>{
e.preventDefault();
shoot();
});
shopBtn.onclick = () => {
if(!gameOver) shopPanel.style.display = "block";
};
closeShop.onclick = () => {
shopPanel.style.display = "none";
};
shopButtons.forEach(btn => {
btn.onclick = () => {
const type = btn.dataset.type;
if(type === "heal"){
if(coin >= 20 && player.hp < player.maxHp){
coin -= 20;
player.hp = Math.min(player.maxHp, player.hp + 20);
}
}else if(type === "speed"){
if(coin >= 50){coin -= 50; player.speed += 1;}
}else if(type === "bulletSpeed"){
if(coin >= 60){coin -= 60; bullets.forEach(b => b.speed += 2);}
}else if(type === "bulletDmg"){
if(coin >= 80){coin -= 80; bulletDamage += 1;}
}else if(type === "fireRate"){
if(coin >= 90){coin -= 90; fireDelay -= 100;}
}else if(type === "coolUp"){
if(coin >= 100){coin -= 100; hurtCoolAdd += 1000;}
}else if(type === "coinBonus"){
if(coin >= 120){coin -= 120; killCoinBonus += 1;}
}else if(type === "maxHp"){
if(coin >= 150){coin -= 150; player.maxHp += 20; player.hp += 20;}
}else if(type === "autoFire"){
if(coin >= 180){coin -= 180; autoFire = true;}
}else if(type === "explodeKill"){
if(coin >= 200){coin -= 200; explodeKill = true;}
}else if(type === "cardTriple"){
if(coin >=100){coin -= 100; playerCards.push({name:"三发爆发",type:"triple"});}
}else if(type === "cardIce"){
if(coin >=140){coin -= 140; playerCards.push({name:"寒冰射手",type:"ice"});}
}else if(type === "cardNut"){
if(coin >=160){coin -= 160; playerCards.push({name:"坚果墙",type:"nut"});}
}
};
});
//使用卡牌
function useCard(cardIndex){
if(gameOver) return;
const card = playerCards[cardIndex];
if(!card) return;
if(card.type === "triple"){
tripleShotTimer = 10000; //持续10秒,玩家每次射击+2发子弹
}else{
const ang = Math.atan2(joyDy || 0, joyDx || 1);
const spawnX = player.x + Math.cos(ang)*70;
const spawnY = player.y + Math.sin(ang)*70;
if(card.type === "ice"){
plants.push({
x:spawnX,y:spawnY,size:44,shootCd:0,shootRate:35,plantType:"ice",hp:80,maxHp:80
});
}else if(card.type === "nut"){
plants.push({
x:spawnX,y:spawnY,size:55,shootCd:0,shootRate:0,plantType:"nut",hp:8000,maxHp:8000
});
}
}
playerCards.splice(cardIndex,1);
}
function spawnEnemy(){
if(gameOver) return;
const side = Math.floor(Math.random() * 4);
let ex, ey;
let type = 0;
let rand = Math.random();
if(rand < 0.7) type = 0;
else if(rand < 0.92) type = 1;
else type = 2;
if(side === 0){ex = 0; ey = Math.random() * canvas.height;}
else if(side === 1){ex = canvas.width; ey = Math.random() * canvas.height;}
else if(side === 2){ex = Math.random() * canvas.width; ey = 0;}
else {ex = Math.random() * canvas.width; ey = canvas.height;}
let enemyData = {
x: ex,
y: ey,
size: 46,
speed: 0.8,
id: Date.now() + Math.random(),
type: type,
hp: 1,
maxHp: 1,
targetPlayer:true //默认目标玩家
};
if(type === 1){
enemyData.speed = 1.1;
enemyData.size = 54;
enemyData.hp = 3;
enemyData.maxHp = 3;
}else if(type === 2){
enemyData.speed = 1.4;
enemyData.size = 62;
enemyData.hp = 5;
enemyData.maxHp = 5;
}
enemies.push(enemyData);
}
function spawnBoss(){
if(boss) return;
boss = {
x: canvas.width / 2,
y: 120,
size: 120,
hp: 200,
maxHp: 200,
speed: 0.35,
dir: 1,
shootCd: 0,
summonCd: 240
};
}
function showCardSelect(){
cardList.innerHTML = "";
const cardPool = [
{name:"❄️僵尸减速",desc:"全体僵尸速度减半,持续10秒",action:()=>{ slowZombieTimer = 10000; }},
{name:"💰双倍铜币",desc:"10秒击杀铜币×2",action:()=>{ doubleCoinTimer = 10000; }},
{name:"🔥穿透子弹",desc:"子弹穿透多个僵尸,持续8秒",action:()=>{ piercingTimer = 8000; }},
{name:"🛡️临时护盾",desc:"5秒免伤",action:()=>{ shieldTimer = 5000; }},
{name:"💀一击秒杀",desc:"接下来5发子弹秒杀",action:()=>{ instantKillCount = 5; }},
{name:"❤️回满血量",desc:"血量直接回满",action:()=>{ player.hp = player.maxHp; }},
{name:"🪙铜币+50",desc:"直接获得50铜币",action:()=>{ coin += 50; }},
{name:"💥冲击波",desc:"清空场上全部僵尸",action:()=>{ bombWaveTimer = 1; }},
{name:"🤖召唤帮手",desc:"豌豆助手打怪12秒",action:()=>{ summonHelperTimer = 12000; helper = {x: player.x, y: player.y}; }},
{name:"🥺僵尸虚弱",desc:"僵尸受到伤害+50%持续10秒",action:()=>{ weakZombieTimer = 10000; }}
];
let shuffled = [...cardPool].sort(() => Math.random() - 0.5).slice(0, 3);
shuffled.forEach((card,idx) => {
let div = document.createElement("div");
div.className = "card-choice";
div.innerHTML = `<div>${card.name}</div><div style="font-size:12px;margin-top:4px">${card.desc}</div>`;
div.onclick = () => {
card.action();
cardPanel.style.display = "none";
};
cardList.appendChild(div);
});
cardPanel.style.display = "block";
}
function loop(){
const paused = shopPanel.style.display === "block" || cardPanel.style.display === "block";
if(!gameOver && !paused){
player.x += joyDx * player.speed;
player.y += joyDy * player.speed;
player.x = Math.max(player.size, Math.min(canvas.width - player.size, player.x));
player.y = Math.max(player.size, Math.min(canvas.height - player.size, player.y));
if(autoFire){
shoot();
}
if(killCount > 0 && killCount % 10 === 0 && cardPanel.style.display !== "block"){
showCardSelect();
killCount += 1;
}
if(killCount >= BOSS_KILL_REQUIRE){
spawnBoss();
}
if(slowZombieTimer > 0) slowZombieTimer -= 16;
if(doubleCoinTimer > 0) doubleCoinTimer -= 16;
if(piercingTimer > 0) piercingTimer -= 16;
if(shieldTimer > 0) shieldTimer -= 16;
if(summonHelperTimer > 0) summonHelperTimer -= 16;
if(weakZombieTimer > 0) weakZombieTimer -= 16;
if(tripleShotTimer > 0) tripleShotTimer -= 16;
if(bombWaveTimer > 0){
bombWaveTimer = 0;
enemies.forEach(e => {
killCount++;
let getCoin = 0;
if(e.type === 0) getCoin = 1 + killCoinBonus;
else if(e.type === 1) getCoin = 5 + killCoinBonus;
else if(e.type === 2) getCoin = 20 + killCoinBonus;
if(doubleCoinTimer > 0) getCoin *= 2;
coin += getCoin;
});
enemies = [];
}
if(summonHelperTimer > 0 && helper){
let nearestEnemy = null;
let minD = 9999;
enemies.forEach(e => {
let d = Math.hypot(e.x - helper.x, e.y - helper.y);
if(d < minD){
minD = d;
nearestEnemy = e;
}
});
if(nearestEnemy){
let ang = Math.atan2(nearestEnemy.y - helper.y, nearestEnemy.x - helper.x);
helper.x += Math.cos(ang) * 3;
helper.y += Math.sin(ang) * 3;
if(Math.hypot(helper.x - nearestEnemy.x, helper.y - nearestEnemy.y) < 30){
nearestEnemy.hp -= 0.08;
}
}
}
let hasIcePlant = plants.some(p=>p.plantType === "ice" && p.hp>0);
// ===== 植物自动攻击 =====
plants.forEach(p => {
p.shootCd--;
if(p.plantType === "nut") return;
if(p.shootCd <= 0 && enemies.length > 0){
let nearest = enemies[0];
let minD = Math.hypot(nearest.x - p.x, nearest.y - p.y);
for(let e of enemies){
let d = Math.hypot(e.x - p.x, e.y - p.y);
if(d < minD){
minD = d;
nearest = e;
}
}
const ang = Math.atan2(nearest.y - p.y, nearest.x - p.x);
if(p.plantType === "ice"){
bullets.push({x:p.x,y:p.y,target:nearest,speed:7,size:12,damage:0.4,pierce:false,fromPlant:true,isIce:true});
p.shootCd = p.shootRate;
}
}
});
for(let i = bullets.length - 1; i >= 0; i--){
const b = bullets[i];
if(!enemies.includes(b.target)){
bullets.splice(i, 1);
continue;
}
let ang = Math.atan2(b.target.y - b.y, b.target.x - b.x);
//子弹角度偏移
if(b.angleOffset) ang += b.angleOffset;
b.x += Math.cos(ang) * b.speed;
b.y += Math.sin(ang) * b.speed;
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];
//僵尸优先找最近坚果墙
let nearestNut = null;
let nutDist = 9999;
plants.forEach(p=>{
if(p.plantType === "nut" && p.hp>0){
let d = Math.hypot(p.x - e.x,p.y - e.y);
if(d < nutDist){
nutDist = d;
nearestNut = p;
}
}
});
if(nearestNut){
e.targetPlayer = false;
const ang = Math.atan2(nearestNut.y - e.y, nearestNut.x - e.x);
e.x += Math.cos(ang)*e.speed;
e.y += Math.sin(ang)*e.speed;
//僵尸啃坚果
if(Math.hypot(e.x-nearestNut.x,e.y-nearestNut.y)<e.size+nearestNut.size){
nearestNut.hp -= 0.05;
if(nearestNut.hp <=0){
plants = plants.filter(x=>x!==nearestNut);
}
}
}else{
e.targetPlayer = true;
let speedMult = slowZombieTimer > 0 ? 0.5 : 1;
if(hasIcePlant) speedMult *= 0.5; //寒冰在场,全体僵尸减速
const ang = Math.atan2(player.y - e.y, player.x - e.x);
e.x += Math.cos(ang) * e.speed * speedMult;
e.y += Math.sin(ang) * e.speed * speedMult;
}
const totalHurtCool = 3000 + hurtCoolAdd;
const hitDist = Math.hypot(player.x - e.x, player.y - e.y);
const now = Date.now();
if(e.targetPlayer && hitDist < player.size + e.size){
if(shieldTimer <= 0 && (!enemyHitCool.has(e.id) || now - enemyHitCool.get(e.id) > totalHurtCool)){
player.hp -= 1;
enemyHitCool.set(e.id, now);
if(player.hp <= 0){
player.hp = 0;
gameOver = true;
}
}
}
for(let j = bullets.length - 1; j >= 0; j--){
const b = bullets[j];
const dist = Math.hypot(b.x - e.x, b.y - e.y);
if(dist < e.size + b.size){
let dmg = b.damage;
if(instantKillCount > 0 && !b.fromPlant){
dmg = 999;
instantKillCount--;
}
if(weakZombieTimer > 0) dmg *= 1.5;
e.hp -= dmg;
if(!b.pierce){
bullets.splice(j, 1);
}
if(e.hp <= 0){
killCount += 1;
let getCoin = 0;
if(e.type === 0) getCoin = 1 + killCoinBonus;
else if(e.type === 1) getCoin = 5 + killCoinBonus;
else if(e.type === 2) getCoin = 20 + killCoinBonus;
if(doubleCoinTimer > 0) getCoin *= 2;
coin += getCoin;
if(explodeKill){
enemies.forEach(ee => {
if(Math.hypot(ee.x - e.x, ee.y - e.y) < 70){
ee.hp -= 2;
}
});
}
enemies.splice(i, 1);
enemyHitCool.delete(e.id);
}
break;
}
}
}
// ===== BOSS逻辑 =====
if(boss){
boss.x += boss.dir * boss.speed;
if(boss.x < 160 || boss.x > canvas.width - 160){
boss.dir *= -1;
}
boss.summonCd--;
if(boss.summonCd <= 0){
boss.summonCd = 300;
for(let k = 0; k < 3; k++){
setTimeout(()=>{
if(!gameOver) spawnEnemy();
}, k * 120);
}
}
const bossHit = Math.hypot(player.x - boss.x, player.y - boss.y);
if(bossHit < player.size + boss.size){
if(shieldTimer <= 0){
player.hp -= 1;
if(player.hp <= 0){
player.hp = 0;
gameOver = true;
}
}
}
for(let j = bullets.length - 1; j >= 0; j--){
const b = bullets[j];
const dist = Math.hypot(b.x - boss.x, b.y - boss.y);
if(dist < boss.size + b.size){
let dmg = b.damage;
if(weakZombieTimer > 0) dmg *= 1.5;
boss.hp -= dmg;
if(!b.pierce){
bullets.splice(j, 1);
}
if(boss.hp <= 0){
coin += 200;
killCount += 10;
boss = null;
}
}
}
}
if(Math.random() < 0.010) spawnEnemy();
}
ctx.fillStyle = "#529c49";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = "#407c3a";
ctx.lineWidth = 1;
for(let x = 0; x < canvas.width; x += 40){
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
for(let y = 0; y < canvas.height; y += 40){
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
// ===== 绘制植物 =====
plants.forEach(p => {
ctx.font = "44px system-ui";
let icon = "🌱";
if(p.plantType === "ice") icon = "❄️";
if(p.plantType === "nut") icon = "🪨";
ctx.fillText(icon, p.x - 22, p.y + 14);
//植物血条
ctx.fillStyle = "#333";
ctx.fillRect(p.x - 25, p.y - 35, 50, 6);
ctx.fillStyle = "#2dff40";
ctx.fillRect(p.x - 25, p.y - 35, 50*(p.hp/p.maxHp),6);
});
ctx.font = "40px system-ui";
enemies.forEach(e => {
let icon = "🧟";
if(e.type === 1) icon = "👹";
if(e.type === 2) icon = "👾";
ctx.fillText(icon, e.x - e.size / 2, e.y + e.size / 3);
const enemyHpW = 44;
ctx.fillStyle = "#333";
ctx.fillRect(e.x - enemyHpW / 2, e.y - e.size - 10, enemyHpW, 6);
ctx.fillStyle = "#ff5555";
ctx.fillRect(e.x - enemyHpW / 2, e.y - e.size - 10, enemyHpW * (e.hp / e.maxHp), 6);
});
ctx.font = "28px system-ui";
bullets.forEach(b => {
if(b.fromPlant){
if(b.isIce){
ctx.fillText("🔵", b.x - 10, b.y + 8);
}else{
ctx.fillText("🟢", b.x - 10, b.y + 8);
}
}else{
ctx.fillText("🔥", b.x - 10, b.y + 8);
}
});
if(summonHelperTimer > 0 && helper){
ctx.font = "44px system-ui";
ctx.fillText("🌱", helper.x - 18, helper.y + 12);
}
ctx.font = "48px system-ui";
ctx.fillText("🔥", player.x - 20, player.y + 14);
// ===== 绘制BOSS =====
if(boss){
ctx.font = "120px system-ui";
ctx.fillText("👑", boss.x - 60, boss.y + 40);
ctx.fillStyle = "#333";
ctx.fillRect(canvas.width / 2 - 200, 30, 400, 18);
ctx.fillStyle = "#ff3333";
ctx.fillRect(canvas.width / 2 - 200, 30, 400 * (boss.hp / boss.maxHp), 18);
ctx.fillStyle = "#fff";
ctx.font = "16px system-ui";
ctx.textAlign = "center";
ctx.fillText("僵王博士", canvas.width / 2, 24);
ctx.textAlign = "left";
}
ctx.fillStyle = "#333";
ctx.fillRect(10, 10, 204, 24);
let hpPercent = player.hp / player.maxHp;
ctx.fillStyle = "#ff3333";
ctx.fillRect(12, 12, 200 * hpPercent, 20);
ctx.fillStyle = "#fff";
ctx.font = "16px system-ui";
ctx.fillText("HP:" + player.hp + "/" + player.maxHp, 15, 28);
ctx.fillStyle = "#fff";
ctx.font = "16px system-ui";
ctx.fillText("🪙铜币:" + coin, 10, 52);
ctx.fillText("💥伤害:" + bulletDamage, 10, 74);
ctx.fillText("🔫射速间隔:" + fireDelay + "ms", 10, 96);
ctx.fillText("🤖自动射击:" + (autoFire ? "开启" : "关闭"), 10, 140);
ctx.fillText("💣击杀爆炸:" + (explodeKill ? "开启" : "关闭"), 10, 162);
ctx.fillText("🌱植物:" + plants.length, 10, 184);
ctx.fillText("🎴卡牌:"+playerCards.length,10,206);
//卡牌列表
playerCards.forEach((c,i)=>{
ctx.fillText(`${i+1}.${c.name}`,10,230+i*24);
})
let statusX = 220;
if(slowZombieTimer > 0){ctx.fillStyle = "#8cf"; ctx.fillText("❄️僵尸减速", statusX, 28); statusX += 90;}
if(doubleCoinTimer > 0){ctx.fillStyle = "#ffc"; ctx.fillText("💰双倍铜币", statusX, 28); statusX += 90;}
if(piercingTimer > 0){ctx.fillStyle = "#f8f"; ctx.fillText("🔥穿透子弹", statusX, 28); statusX += 90;}
if(shieldTimer > 0){ctx.fillStyle = "#0cf"; ctx.fillText("🛡️护盾", statusX, 28); statusX += 90;}
if(instantKillCount > 0){ctx.fillStyle = "#f44"; ctx.fillText("💀秒杀剩余:" + instantKillCount, statusX, 28); statusX += 90;}
if(summonHelperTimer > 0){ctx.fillStyle = "#4f8"; ctx.fillText("🤖帮手", statusX, 50); statusX += 90;}
if(weakZombieTimer > 0){ctx.fillStyle = "#fa8"; ctx.fillText("🥺僵尸虚弱", statusX, 50); statusX += 90;}
if(hasIcePlant){ctx.fillStyle="#8cf";ctx.fillText("❄️全场减速",statusX,50);statusX+=90;}
if(tripleShotTimer > 0){ctx.fillStyle="#ff9";ctx.fillText("🔥三发爆发",statusX,28);statusX +=90;}
if(gameOver){
ctx.fillStyle = "rgba(0,0,0,0.7)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#ff4444";
ctx.font = "50px system-ui";
ctx.textAlign = "center";
ctx.fillText("游戏结束", canvas.width / 2, canvas.height / 2 - 30);
ctx.font = "24px system-ui";
ctx.fillText("刷新页面重新游玩", canvas.width / 2, canvas.height / 2 + 20);
ctx.textAlign = "left";
}
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>Game Source: 火焰豌豆大冒险
Creator: MysticPanda75
Libraries: none
Complexity: complex (745 lines, 24.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: game-mysticpanda75-mvf75lkn" to link back to the original. Then publish at arcadelab.ai/publish.