Skip to content

Commit 70de1b4

Browse files
authored
Create index.html
1 parent 2946f5b commit 70de1b4

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

basic-zombie-game/index.html

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6+
<title>PvZ Browser Game</title>
7+
<style>
8+
body { margin: 0; overflow: hidden; background: #222; color: white; font-family: Arial; }
9+
canvas { display: block; background: #333; margin: 0 auto; }
10+
#overlay {
11+
position: absolute; top: 10px; left: 10px;
12+
background: rgba(0,0,0,0.7); padding: 10px; border: 2px solid #fff;
13+
}
14+
#health-bar {
15+
width: 200px; height: 20px; background: #555; margin-bottom: 10px;
16+
}
17+
#health-fill { height: 100%; width: 100%; background: red; }
18+
</style>
19+
</head>
20+
<body>
21+
22+
<div id="overlay">
23+
<div id="health-bar"><div id="health-fill"></div></div>
24+
<p>Wave: <span id="wave">1</span></p>
25+
<p>Coins: <span id="coins">0</span></p>
26+
<button onclick="startNextWave()">Start Wave</button>
27+
</div>
28+
29+
<canvas id="game" width="800" height="600"></canvas>
30+
31+
<!-- Sound effects -->
32+
<audio id="shoot-sfx" src="https://freesound.org/data/previews/341/341695_6263744-lq.mp3"></audio>
33+
<audio id="zombie-dead-sfx" src="https://freesound.org/data/previews/341/341668_6263744-lq.mp3"></audio>
34+
35+
<script>
36+
const canvas = document.getElementById("game"), ctx = canvas.getContext("2d");
37+
const shootSfx = document.getElementById("shoot-sfx"),
38+
deadSfx = document.getElementById("zombie-dead-sfx");
39+
40+
let player = { x:400, y:300, size:20, speed:3, damage:1, maxHealth:100, health:100 };
41+
let zombies = [], bullets = [];
42+
let keys = {}, coins = 0, wave = 0, zombieSpeed = 1.0, waveActive = false;
43+
44+
// UI hooks
45+
const healthFill = document.getElementById("health-fill");
46+
const waveDisplay = document.getElementById("wave");
47+
const coinsDisplay = document.getElementById("coins");
48+
49+
function updateUI(){
50+
healthFill.style.width = (player.health / player.maxHealth * 100) + "%";
51+
waveDisplay.textContent = wave;
52+
coinsDisplay.textContent = coins;
53+
}
54+
55+
function spawnWave(){
56+
wave++;
57+
zombies = [];
58+
bullets = [];
59+
zombieSpeed = 1 + wave * 0.2;
60+
for(let i=0; i<wave*5; i++){
61+
let edge = Math.floor(Math.random()*4);
62+
let x = edge===0?0:edge===1?canvas.width:Math.random()*canvas.width;
63+
let y = edge===2?0:edge===3?canvas.height:Math.random()*canvas.height;
64+
zombies.push({ x, y, size:20, hp:3 + wave, id: Date.now()+i });
65+
}
66+
waveActive = true;
67+
updateUI();
68+
}
69+
70+
function startNextWave(){ if(!waveActive) spawnWave(); }
71+
72+
function update(){
73+
if(player.health<=0){ waveActive = false; return; }
74+
if(keys.w) player.y -= player.speed;
75+
if(keys.s) player.y += player.speed;
76+
if(keys.a) player.x -= player.speed;
77+
if(keys.d) player.x += player.speed;
78+
player.x = Math.max(0,Math.min(canvas.width,player.x));
79+
player.y = Math.max(0,Math.min(canvas.height,player.y));
80+
81+
zombies.forEach((z,i) => {
82+
let dx = player.x - z.x, dy = player.y - z.y;
83+
let dist = Math.hypot(dx,dy);
84+
if(dist < z.size + player.size){
85+
player.health -= 0.3;
86+
if(player.health < 0) player.health = 0;
87+
} else {
88+
z.x += (dx / dist)*zombieSpeed;
89+
z.y += (dy / dist)*zombieSpeed;
90+
}
91+
if(z.hp <= 0){
92+
zombies.splice(i,1);
93+
coins += 5;
94+
deadSfx.currentTime = 0;
95+
deadSfx.play();
96+
updateUI();
97+
}
98+
});
99+
100+
bullets.forEach((b, bi) => {
101+
b.x += b.dx*5; b.y += b.dy*5;
102+
if(b.x <0||b.x>canvas.width||b.y<0||b.y>canvas.height){
103+
bullets.splice(bi,1);
104+
return;
105+
}
106+
zombies.forEach((z, zi) => {
107+
if(Math.hypot(b.x-z.x, b.y-z.y) < z.size){
108+
z.hp -= player.damage;
109+
bullets.splice(bi,1);
110+
}
111+
});
112+
});
113+
114+
if(waveActive && zombies.length===0){
115+
waveActive = false;
116+
}
117+
}
118+
119+
function draw(){
120+
ctx.clearRect(0,0,canvas.width,canvas.height);
121+
ctx.fillStyle = player.color || 'cyan';
122+
ctx.beginPath(); ctx.arc(player.x,player.y,player.size,0,2*Math.PI); ctx.fill();
123+
zombies.forEach(z => {
124+
ctx.fillStyle = "green";
125+
ctx.beginPath(); ctx.arc(z.x,z.y,z.size,0,2*Math.PI); ctx.fill();
126+
});
127+
bullets.forEach(b => {
128+
ctx.fillStyle = "yellow";
129+
ctx.beginPath(); ctx.arc(b.x,b.y,5,0,2*Math.PI); ctx.fill();
130+
});
131+
}
132+
133+
function gameLoop(){
134+
update(); draw();
135+
if(player.health <= 0){
136+
ctx.fillStyle='red';
137+
ctx.font='48px sans-serif';
138+
ctx.fillText('Game Over', 300,300);
139+
} else {
140+
requestAnimationFrame(gameLoop);
141+
}
142+
}
143+
gameLoop();
144+
145+
document.addEventListener("keydown",e=>keys[e.key.toLowerCase()]=true);
146+
document.addEventListener("keyup",e=>keys[e.key.toLowerCase()]=false);
147+
canvas.addEventListener("click",e=>{
148+
if(!waveActive) return;
149+
let angle = Math.atan2(e.clientY-player.y, e.clientX-player.x);
150+
bullets.push({ x:player.x, y:player.y, dx:Math.cos(angle), dy:Math.sin(angle) });
151+
shootSfx.currentTime = 0; shootSfx.play();
152+
});
153+
154+
155+
156+
updateUI();
157+
</script>
158+
159+
</body>
160+
</html>

0 commit comments

Comments
 (0)