Spaces:
Running
Running
Update index.html
Browse files- index.html +33 -35
index.html
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
-
<meta charset="UTF-8">
|
5 |
<style>
|
6 |
body {
|
7 |
margin: 0;
|
@@ -96,10 +95,7 @@
|
|
96 |
const PLAYER_SIZE = 30;
|
97 |
const BULLET_SPEED = 10;
|
98 |
const ENEMY_SPEED = 2;
|
99 |
-
const SHOOTING_INTERVAL = 333;
|
100 |
-
|
101 |
-
// Base64 encoded shot sound (very short beep)
|
102 |
-
const SHOT_SOUND = 'data:audio/wav;base64,UklGRigCAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQQCAACBhYqFbF1pbphwX4WqY0J0zGYhdPV3I2vyd5qCvHKTlZJ0j6p+cJGYhIaHmH1li6R9YH6hooCEjaB0f4SOo3yLkZSCeq+bXY/FdWt9tnhcl69yZ5mfdGSSoYKEkZuBdYqgeIKEm4Joe6GJfX+VmnuBjZaFhqmQYY7Hc36QiXd6kpWLgpSieIeQnICEkZeEhJOcfH6Om4GBjZWEgpOYfICLl4OBjZSEgZKYfICKloKBjJODgZGXe3+JlYGAi5KCgJCWen+IlICAfoh+gY2ScICBjX+ChImFhYuJhYeHhoeHh4iIiIiIiIiIiIiIiIiIiIiI';
|
103 |
|
104 |
let game = {
|
105 |
player: {
|
@@ -120,29 +116,7 @@
|
|
120 |
shooting: false
|
121 |
};
|
122 |
|
123 |
-
|
124 |
-
let audioContext;
|
125 |
-
document.addEventListener('click', initAudio, { once: true });
|
126 |
-
document.addEventListener('keydown', initAudio, { once: true });
|
127 |
-
|
128 |
-
function initAudio() {
|
129 |
-
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
130 |
-
}
|
131 |
-
|
132 |
-
function playShot() {
|
133 |
-
if (!audioContext) return;
|
134 |
-
|
135 |
-
fetch(SHOT_SOUND)
|
136 |
-
.then(response => response.arrayBuffer())
|
137 |
-
.then(buffer => audioContext.decodeAudioData(buffer))
|
138 |
-
.then(decodedData => {
|
139 |
-
const source = audioContext.createBufferSource();
|
140 |
-
source.buffer = decodedData;
|
141 |
-
source.connect(audioContext.destination);
|
142 |
-
source.start(0);
|
143 |
-
})
|
144 |
-
.catch(err => console.log('Sound play failed:', err));
|
145 |
-
}
|
146 |
|
147 |
function spawnEnemies() {
|
148 |
const enemyCount = game.round * 5;
|
@@ -187,7 +161,7 @@
|
|
187 |
angle: angle + (Math.random() - 0.5) * 0.2
|
188 |
});
|
189 |
}
|
190 |
-
|
191 |
game.lastShot = Date.now();
|
192 |
}
|
193 |
|
@@ -197,12 +171,13 @@
|
|
197 |
bullet.x += Math.cos(bullet.angle) * BULLET_SPEED;
|
198 |
bullet.y += Math.sin(bullet.angle) * BULLET_SPEED;
|
199 |
|
|
|
200 |
if(bullet.x < 0 || bullet.x > canvas.width ||
|
201 |
bullet.y < 0 || bullet.y > canvas.height) {
|
202 |
game.player.bullets.splice(i, 1);
|
203 |
-
continue;
|
204 |
}
|
205 |
|
|
|
206 |
for(let j = game.enemies.length - 1; j >= 0; j--) {
|
207 |
const enemy = game.enemies[j];
|
208 |
const dx = bullet.x - enemy.x;
|
@@ -213,6 +188,7 @@
|
|
213 |
if(enemy.health <= 0) {
|
214 |
game.enemies.splice(j, 1);
|
215 |
game.player.bulletsPerShot++;
|
|
|
216 |
game.items.push({
|
217 |
x: enemy.x,
|
218 |
y: enemy.y,
|
@@ -226,12 +202,15 @@
|
|
226 |
|
227 |
// Update enemies
|
228 |
game.enemies.forEach(enemy => {
|
|
|
229 |
enemy.x += enemy.direction.x * ENEMY_SPEED;
|
230 |
enemy.y += enemy.direction.y * ENEMY_SPEED;
|
231 |
|
|
|
232 |
if(enemy.x < 0 || enemy.x > canvas.width) enemy.direction.x *= -1;
|
233 |
if(enemy.y < 0 || enemy.y > canvas.height) enemy.direction.y *= -1;
|
234 |
|
|
|
235 |
if(Date.now() - enemy.lastShot > 1000) {
|
236 |
const angle = Math.atan2(
|
237 |
game.player.y - enemy.y,
|
@@ -245,11 +224,13 @@
|
|
245 |
enemy.lastShot = Date.now();
|
246 |
}
|
247 |
|
|
|
248 |
for(let i = enemy.bullets.length - 1; i >= 0; i--) {
|
249 |
const bullet = enemy.bullets[i];
|
250 |
bullet.x += Math.cos(bullet.angle) * BULLET_SPEED/2;
|
251 |
bullet.y += Math.sin(bullet.angle) * BULLET_SPEED/2;
|
252 |
|
|
|
253 |
const dx = bullet.x - game.player.x;
|
254 |
const dy = bullet.y - game.player.y;
|
255 |
if(Math.sqrt(dx*dx + dy*dy) < PLAYER_SIZE/2) {
|
@@ -263,6 +244,7 @@
|
|
263 |
}
|
264 |
}
|
265 |
|
|
|
266 |
if(bullet.x < 0 || bullet.x > canvas.width ||
|
267 |
bullet.y < 0 || bullet.y > canvas.height) {
|
268 |
enemy.bullets.splice(i, 1);
|
@@ -293,7 +275,7 @@
|
|
293 |
document.getElementById('round').textContent = `Round ${game.round}`;
|
294 |
game.player.health = game.player.maxHealth;
|
295 |
document.getElementById('health').style.width = '100%';
|
296 |
-
game.player.bulletsPerShot = 1;
|
297 |
spawnEnemies();
|
298 |
}
|
299 |
}
|
@@ -303,9 +285,9 @@
|
|
303 |
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
304 |
|
305 |
// Draw player
|
306 |
-
ctx.font = '24px Arial';
|
307 |
ctx.fillStyle = 'white';
|
308 |
-
ctx.
|
|
|
309 |
|
310 |
// Draw player bullets
|
311 |
ctx.fillStyle = 'yellow';
|
@@ -319,7 +301,7 @@
|
|
319 |
game.enemies.forEach(enemy => {
|
320 |
// Enemy
|
321 |
ctx.fillStyle = 'white';
|
322 |
-
ctx.fillText('
|
323 |
|
324 |
// Health bar
|
325 |
ctx.fillStyle = '#600';
|
@@ -380,4 +362,20 @@
|
|
380 |
// Event listeners
|
381 |
window.addEventListener('keydown', e => game.keys[e.key] = true);
|
382 |
window.addEventListener('keyup', e => game.keys[e.key] = false);
|
383 |
-
window.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
|
|
4 |
<style>
|
5 |
body {
|
6 |
margin: 0;
|
|
|
95 |
const PLAYER_SIZE = 30;
|
96 |
const BULLET_SPEED = 10;
|
97 |
const ENEMY_SPEED = 2;
|
98 |
+
const SHOOTING_INTERVAL = 333; // 3 shots per second
|
|
|
|
|
|
|
99 |
|
100 |
let game = {
|
101 |
player: {
|
|
|
116 |
shooting: false
|
117 |
};
|
118 |
|
119 |
+
const gunSound = new Audio('data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YWoGAACBhYqFbF1pbphwX4WqY0J0zGYhdPV3I2vyd5qCvHKTlZJ0j6p+cJGYhIaHmH1li6R9YH6hooCEjaB0f4SOo3yLkZSCeq+bXY/FdWt9tnhcl69yZ5mfdGSSoYKEkZuBdYqgeIKEm4Joe6GJfX+VmnuBjZaFhqmQYY7Hc36QiXd6kpWLgpSieIeQnICEkZeEhJOcfH6Om4GBjZWEgpOYfICLl4OBjZSEgZKYfICKloKBjJODgZGXe3+JlYGAi5KCgJCWen+IlICAfoh+gY2ScICBjX+ChImFhYuJhYeHhoeHh4iIiIiIiIiIiIiIiIiIiIiIiIiHh4aGhYSCgYB/fn18fHx9fn+AgYKEhYeIiYuMjo+RkpSVl5iZmptcW15hZGhrbW5vcHFydHZ4enx+gIKEh4mMj5GSk5OTkpGQjo2LiomIiImKi4yOj5GSlJWXmJqbnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drbAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8=');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
function spawnEnemies() {
|
122 |
const enemyCount = game.round * 5;
|
|
|
161 |
angle: angle + (Math.random() - 0.5) * 0.2
|
162 |
});
|
163 |
}
|
164 |
+
gunSound.cloneNode().play();
|
165 |
game.lastShot = Date.now();
|
166 |
}
|
167 |
|
|
|
171 |
bullet.x += Math.cos(bullet.angle) * BULLET_SPEED;
|
172 |
bullet.y += Math.sin(bullet.angle) * BULLET_SPEED;
|
173 |
|
174 |
+
// Remove out of bounds bullets
|
175 |
if(bullet.x < 0 || bullet.x > canvas.width ||
|
176 |
bullet.y < 0 || bullet.y > canvas.height) {
|
177 |
game.player.bullets.splice(i, 1);
|
|
|
178 |
}
|
179 |
|
180 |
+
// Check enemy hits
|
181 |
for(let j = game.enemies.length - 1; j >= 0; j--) {
|
182 |
const enemy = game.enemies[j];
|
183 |
const dx = bullet.x - enemy.x;
|
|
|
188 |
if(enemy.health <= 0) {
|
189 |
game.enemies.splice(j, 1);
|
190 |
game.player.bulletsPerShot++;
|
191 |
+
// Drop health item
|
192 |
game.items.push({
|
193 |
x: enemy.x,
|
194 |
y: enemy.y,
|
|
|
202 |
|
203 |
// Update enemies
|
204 |
game.enemies.forEach(enemy => {
|
205 |
+
// Movement
|
206 |
enemy.x += enemy.direction.x * ENEMY_SPEED;
|
207 |
enemy.y += enemy.direction.y * ENEMY_SPEED;
|
208 |
|
209 |
+
// Bounce off walls
|
210 |
if(enemy.x < 0 || enemy.x > canvas.width) enemy.direction.x *= -1;
|
211 |
if(enemy.y < 0 || enemy.y > canvas.height) enemy.direction.y *= -1;
|
212 |
|
213 |
+
// Shooting
|
214 |
if(Date.now() - enemy.lastShot > 1000) {
|
215 |
const angle = Math.atan2(
|
216 |
game.player.y - enemy.y,
|
|
|
224 |
enemy.lastShot = Date.now();
|
225 |
}
|
226 |
|
227 |
+
// Update enemy bullets
|
228 |
for(let i = enemy.bullets.length - 1; i >= 0; i--) {
|
229 |
const bullet = enemy.bullets[i];
|
230 |
bullet.x += Math.cos(bullet.angle) * BULLET_SPEED/2;
|
231 |
bullet.y += Math.sin(bullet.angle) * BULLET_SPEED/2;
|
232 |
|
233 |
+
// Check player hit
|
234 |
const dx = bullet.x - game.player.x;
|
235 |
const dy = bullet.y - game.player.y;
|
236 |
if(Math.sqrt(dx*dx + dy*dy) < PLAYER_SIZE/2) {
|
|
|
244 |
}
|
245 |
}
|
246 |
|
247 |
+
// Remove out of bounds bullets
|
248 |
if(bullet.x < 0 || bullet.x > canvas.width ||
|
249 |
bullet.y < 0 || bullet.y > canvas.height) {
|
250 |
enemy.bullets.splice(i, 1);
|
|
|
275 |
document.getElementById('round').textContent = `Round ${game.round}`;
|
276 |
game.player.health = game.player.maxHealth;
|
277 |
document.getElementById('health').style.width = '100%';
|
278 |
+
game.player.bulletsPerShot = 1; // Reset bullets per shot
|
279 |
spawnEnemies();
|
280 |
}
|
281 |
}
|
|
|
285 |
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
286 |
|
287 |
// Draw player
|
|
|
288 |
ctx.fillStyle = 'white';
|
289 |
+
ctx.font = '30px Arial';
|
290 |
+
ctx.fillText('🐭', game.player.x - 15, game.player.y + 15);
|
291 |
|
292 |
// Draw player bullets
|
293 |
ctx.fillStyle = 'yellow';
|
|
|
301 |
game.enemies.forEach(enemy => {
|
302 |
// Enemy
|
303 |
ctx.fillStyle = 'white';
|
304 |
+
ctx.fillText('🐱', enemy.x - 15, enemy.y + 15);
|
305 |
|
306 |
// Health bar
|
307 |
ctx.fillStyle = '#600';
|
|
|
362 |
// Event listeners
|
363 |
window.addEventListener('keydown', e => game.keys[e.key] = true);
|
364 |
window.addEventListener('keyup', e => game.keys[e.key] = false);
|
365 |
+
window.addEventListener('mousemove', e => {
|
366 |
+
game.mouse.x = e.clientX;
|
367 |
+
game.mouse.y = e.clientY;
|
368 |
+
});
|
369 |
+
window.addEventListener('keydown', e => {
|
370 |
+
if(e.code === 'Space') game.shooting = true;
|
371 |
+
});
|
372 |
+
window.addEventListener('keyup', e => {
|
373 |
+
if(e.code === 'Space') game.shooting = false;
|
374 |
+
});
|
375 |
+
|
376 |
+
// Start game
|
377 |
+
spawnEnemies();
|
378 |
+
gameLoop();
|
379 |
+
</script>
|
380 |
+
</body>
|
381 |
+
</html><script async data-explicit-opt-in="true" data-cookie-opt-in="true" src="https://vercel.live/_next-live/feedback/feedback.js"></script>
|