console
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>红草坪塔防</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #222;
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
color: white;
font-family: Microsoft YaHei;
}
#gameBox {
position: relative;
width: 800px;
height: 500px;
background-color: #992222;
border: 4px solid #440000;
overflow: hidden;
}
.grid {
position: absolute;
border: 1px solid rgba(255,255,255,0.15);
width: 80px;
height: 100px;
}
.plant {
position: absolute;
width:70px;
height:90px;
text-align:center;
color:white;
font-size:11px;
display:flex;
align-items:center;
justify-content:center;
border-radius:8px;
background:rgba(30,120,30,0.7);
}
.zombie {
position:absolute;
width:70px;
height:90px;
color:white;
font-size:11px;
display:flex;
align-items:center;
justify-content:center;
background:rgba(120,120,60,0.7);
border-radius:6px;
}
.zombie.enrage{
background:rgba(180,40,40,0.8);
}
.zombie.stuck{
background:#4488ff;
}
.bullet {
position:absolute;
width:12px;
height:12px;
background-color:#ff2222;
border-radius:50%;
}
#ui{
margin:10px 0;
display:flex;
gap:6px;
flex-wrap:wrap;
justify-content:center;
}
button{
padding:7px 10px;
font-size:13px;
}
#sunText{
font-size:20px;
color:#ffdd33;
margin:8px;
}
</style>
</head>
<body>
<h2>红草坪塔防</h2>
<div id="sunText">☀阳光:150</div>
<div id="ui">
<button id="btnWave">开始一波僵尸</button>
</div>
<div id="gameBox"></div>
<script>
const gameBox = document.getElementById("gameBox");
const GRID_W = 80;
const GRID_H = 100;
const ROWS = 5;
const COLS = 9;
let plants = [];
let zombies = [];
let bullets = [];
let sunCount =150;
let selectedPlant = null;
//绘制网格
for(let r=0;r<ROWS;r++){
for(let c=0;c<COLS;c++){
const g = document.createElement("div");
g.className="grid";
g.style.left = c*GRID_W +"px";
g.style.top = r*GRID_H +"px";
gameBox.appendChild(g);
g.onclick = ()=>{
if(!selectedPlant) return;
const exist = plants.some(p=>p.col === c && p.row === r);
if(exist) return;
placePlant(selectedPlant,c,r);
selectedPlant=null;
}
}
}
const plantData = {
pea:{name:"独眼豌豆射手",cost:100},
sunflower:{name:"向日葵",cost:75},
nut:{name:"坚果墙",cost:50},
chomper:{name:"大嘴花",cost:150},
spike:{name:"地刺",cost:125}
}
const uiDiv = document.getElementById("ui");
for(const key in plantData){
const p = plantData[key];
const btn = document.createElement("button");
btn.innerText = p.name+"("+p.cost+"☀)";
btn.onclick = ()=>{
if(sunCount >= p.cost){
selectedPlant = key;
}
}
uiDiv.appendChild(btn);
}
function placePlant(type,col,row){
const pDiv = document.createElement("div");
pDiv.className="plant";
pDiv.innerText = plantData[type].name;
pDiv.style.left = col*GRID_W +5 +"px";
pDiv.style.top = row*GRID_H +5 +"px";
gameBox.appendChild(pDiv);
plants.push({
type,col,row,dom:pDiv,hp:100,shootTimer:0
})
}
document.getElementById("btnWave").onclick = ()=>{
for(let i=0;i<4;i++){
const zDiv = document.createElement("div");
zDiv.className="zombie";
let zType;
if(i===3) zType="iron";
else if(i===2) zType="cone";
else zType="normal";
let nameText = "普通僵尸";
if(zType==="cone") nameText="路障僵尸";
if(zType==="iron") nameText="血迹铁桶僵尸";
zDiv.innerText = nameText;
const r = Math.floor(Math.random()*ROWS);
const zObj = {
type:zType,
row:r,
x:720,
dom:zDiv,
hp:80,
hitBullet:0,
enraged:false,
stuck:false,
stuckTimer:0
}
zDiv.style.left = zObj.x +"px";
zDiv.style.top = r*GRID_H +5 +"px";
gameBox.appendChild(zDiv);
zombies.push(zObj);
}
}
function gameLoop(){
plants.forEach(p=>{
if(p.type === "pea"){
p.shootTimer++;
if(p.shootTimer>60){
p.shootTimer=0;
const bDiv = document.createElement("div");
bDiv.className="bullet";
const bulletX = p.col*GRID_W +70;
const bulletY = p.row*GRID_H +45;
bDiv.style.left = bulletX +"px";
bDiv.style.top = bulletY +"px";
gameBox.appendChild(bDiv);
bullets.push({
x:bulletX,
y:bulletY,
row:p.row,
dom:bDiv
})
}
}
})
bullets.forEach(b=>{
b.x +=6;
b.dom.style.left = b.x +"px";
zombies.forEach(z=>{
if(z.row === b.row && Math.abs(b.x - z.x)<30){
b.dom.remove();
b.hit = true;
z.hitBullet++;
if(z.type==="normal" && z.hitBullet>=5 && !z.enraged){
z.enraged=true;
z.dom.classList.add("enrage");
}
}
})
})
bullets = bullets.filter(b=>!b.hit && b.x<800);
zombies.forEach(z=>{
if(z.stuck){
z.stuckTimer--;
if(z.stuckTimer<=0){
z.stuck=false;
z.dom.classList.remove("stuck");
}
return;
}
plants.forEach(p=>{
if(p.type==="spike" && p.row===z.row && Math.abs(z.x - p.col*GRID_W)<60){
if(Math.random()<0.21){
z.stuck=true;
z.stuckTimer=120;
z.dom.classList.add("stuck");
}
}
})
if(!z.enraged){
z.x -=0.4;
}else{
z.x -=0.7;
}
z.dom.style.left = z.x +"px";
})
requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>