sagar007 commited on
Commit
44f5324
·
verified ·
1 Parent(s): 9d6876b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -19
app.py CHANGED
@@ -1,6 +1,6 @@
1
  import gradio as gr
2
 
3
- # Updated HTML with fixes and debugging
4
  game_html = """
5
  <!DOCTYPE html>
6
  <html>
@@ -23,7 +23,9 @@ game_html = """
23
  <button id="restart-button">Restart</button>
24
  </div>
25
  <script>
26
- document.addEventListener('DOMContentLoaded', () => {
 
 
27
  const gameCanvas = document.getElementById('game-canvas');
28
  const scoreDisplay = document.getElementById('score');
29
  const gameOverDisplay = document.getElementById('game-over');
@@ -32,7 +34,9 @@ game_html = """
32
  let gameRunning = true;
33
  let birds = [];
34
  let explosions = [];
35
-
 
 
36
  function createClouds() {
37
  const cloudCount = 5;
38
  for (let i = 0; i < cloudCount; i++) {
@@ -55,7 +59,7 @@ game_html = """
55
  gameCanvas.appendChild(cloudPart);
56
  }
57
  }
58
-
59
  class Bird {
60
  constructor() {
61
  this.x = -50;
@@ -66,6 +70,7 @@ game_html = """
66
  gameCanvas.appendChild(this.element);
67
  console.log('Bird created at x:', this.x, 'y:', this.y);
68
  }
 
69
  createBirdElement() {
70
  const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
71
  const body = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
@@ -75,22 +80,26 @@ game_html = """
75
  body.setAttribute("ry", this.size / 3);
76
  body.setAttribute("fill", this.getRandomColor());
77
  group.appendChild(body);
 
78
  const head = document.createElementNS("http://www.w3.org/2000/svg", "circle");
79
  head.setAttribute("cx", this.size / 2);
80
  head.setAttribute("cy", -this.size / 6);
81
  head.setAttribute("r", this.size / 4);
82
  head.setAttribute("fill", this.getRandomColor());
83
  group.appendChild(head);
 
84
  const eye = document.createElementNS("http://www.w3.org/2000/svg", "circle");
85
  eye.setAttribute("cx", this.size / 2 + this.size / 8);
86
  eye.setAttribute("cy", -this.size / 6 - this.size / 8);
87
  eye.setAttribute("r", this.size / 10);
88
  eye.setAttribute("fill", "black");
89
  group.appendChild(eye);
 
90
  const beak = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
91
  beak.setAttribute("points", `${this.size / 2 + this.size / 4},-${this.size / 6} ${this.size},0 ${this.size / 2 + this.size / 4},${this.size / 10}`);
92
  beak.setAttribute("fill", "orange");
93
  group.appendChild(beak);
 
94
  const wing = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
95
  wing.setAttribute("cx", "0");
96
  wing.setAttribute("cy", this.size / 4);
@@ -99,20 +108,25 @@ game_html = """
99
  wing.setAttribute("fill", this.getRandomColor());
100
  wing.setAttribute("class", "wing");
101
  group.appendChild(wing);
 
102
  return group;
103
  }
 
104
  getRandomColor() {
105
  const colors = ["#FF5733", "#33FF57", "#3357FF", "#F3FF33", "#FF33F3", "#33FFF3"];
106
  return colors[Math.floor(Math.random() * colors.length)];
107
  }
 
108
  update() {
109
  this.x += this.speed;
110
  this.element.setAttribute("transform", `translate(${this.x}, ${this.y})`);
 
111
  const wing = this.element.querySelector(".wing");
112
  if (wing) {
113
  const wingAngle = 15 * Math.sin(Date.now() / 100);
114
  wing.setAttribute("transform", `rotate(${wingAngle})`);
115
  }
 
116
  if (this.x > 850) {
117
  this.remove();
118
  console.log('Bird removed, remaining birds:', birds.length);
@@ -120,11 +134,13 @@ game_html = """
120
  }
121
  return true;
122
  }
 
123
  remove() {
124
- if (this.element.parentNode) {
125
  gameCanvas.removeChild(this.element);
126
  }
127
  }
 
128
  checkHit(x, y) {
129
  const birdX = this.x;
130
  const birdY = this.y;
@@ -132,7 +148,7 @@ game_html = """
132
  return distance < this.size;
133
  }
134
  }
135
-
136
  class Explosion {
137
  constructor(x, y, size) {
138
  this.x = x;
@@ -144,10 +160,12 @@ game_html = """
144
  gameCanvas.appendChild(this.element);
145
  this.playSound();
146
  }
 
147
  createExplosionElement() {
148
  const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
149
  const colors = ["#FF0000", "#FF7700", "#FFFF00"];
150
  const particleCount = 12;
 
151
  for (let i = 0; i < particleCount; i++) {
152
  const angle = (i / particleCount) * 2 * Math.PI;
153
  const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
@@ -159,6 +177,7 @@ game_html = """
159
  circle.setAttribute("data-angle", angle);
160
  group.appendChild(circle);
161
  }
 
162
  const center = document.createElementNS("http://www.w3.org/2000/svg", "circle");
163
  center.setAttribute("cx", 0);
164
  center.setAttribute("cy", 0);
@@ -167,20 +186,24 @@ game_html = """
167
  center.setAttribute("class", "center");
168
  group.appendChild(center);
169
  group.setAttribute("transform", `translate(${this.x}, ${this.y})`);
 
170
  return group;
171
  }
 
172
  playSound() {
173
  const explosion = new Audio();
174
  explosion.src = "data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=";
175
  explosion.volume = 0.3;
176
  explosion.play();
177
  }
 
178
  update() {
179
  this.frame++;
180
  const center = this.element.querySelector(".center");
181
  const sizeMultiplier = 1 + this.frame / 5;
182
  center.setAttribute("r", (this.size / 2) * sizeMultiplier);
183
  center.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
 
184
  const particles = this.element.querySelectorAll(".particle");
185
  particles.forEach(particle => {
186
  const angle = parseFloat(particle.getAttribute("data-angle"));
@@ -192,66 +215,91 @@ game_html = """
192
  particle.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
193
  particle.setAttribute("r", this.size / 8 * (1 - this.frame / this.maxFrames));
194
  });
 
195
  if (this.frame >= this.maxFrames) {
196
  this.remove();
197
  return false;
198
  }
199
  return true;
200
  }
 
201
  remove() {
202
- if (this.element.parentNode) {
203
  gameCanvas.removeChild(this.element);
204
  }
205
  }
206
  }
207
-
208
  function initGame() {
209
  score = 0;
210
  gameRunning = true;
211
  scoreDisplay.textContent = `Score: ${score}`;
212
  gameOverDisplay.style.display = 'none';
213
  restartButton.style.display = 'none';
 
 
214
  birds.forEach(bird => bird.remove());
215
  explosions.forEach(explosion => explosion.remove());
216
  birds = [];
217
  explosions = [];
 
 
218
  while (gameCanvas.firstChild) {
219
  gameCanvas.removeChild(gameCanvas.firstChild);
220
  }
 
221
  createClouds();
222
  birds.push(new Bird()); // Start with one bird
 
223
  console.log('Game initialized');
 
 
 
 
 
224
  gameLoop();
225
  }
226
-
227
  function gameLoop() {
228
  if (!gameRunning) {
229
  console.log('Game stopped');
230
  return;
231
  }
232
- console.log('Game loop running, birds:', birds.length);
233
- if (Math.random() < 0.1) { // Increased spawn rate for testing
 
 
234
  birds.push(new Bird());
235
- console.log('New bird spawned');
 
236
  }
 
 
237
  for (let i = birds.length - 1; i >= 0; i--) {
238
  if (!birds[i].update()) {
239
  birds.splice(i, 1);
240
  }
241
  }
 
 
242
  for (let i = explosions.length - 1; i >= 0; i--) {
243
  if (!explosions[i].update()) {
244
  explosions.splice(i, 1);
245
  }
246
  }
247
- requestAnimationFrame(gameLoop); // Ensure continuous looping
 
 
248
  }
249
-
 
250
  gameCanvas.addEventListener('click', (e) => {
251
  if (!gameRunning) return;
 
252
  const rect = gameCanvas.getBoundingClientRect();
253
  const x = e.clientX - rect.left;
254
  const y = e.clientY - rect.top;
 
255
  let hit = false;
256
  for (let i = birds.length - 1; i >= 0; i--) {
257
  if (birds[i].checkHit(x, y)) {
@@ -267,6 +315,7 @@ game_html = """
267
  console.log('Bird hit, score:', score);
268
  }
269
  }
 
270
  if (!hit) {
271
  const miss = new Audio();
272
  miss.src = "data:audio/wav;base64,UklGRiQDAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YQADAABkAGQAZABkAGQAfACEAJwAsAC8AMgA1ADsAOQA7ADkANQA0AC8AKgAnACMAHQAXABMAEQAPABEADwANAA0ADQALAAsACQAHAAUAAwABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA8AFgAaAB8AIQAnACsAMAAyADMANwA3ADcAMgA0ADAALAApACQAIQAbABYAEQAMAAUAAAAAAAAAAAAAAAAAAAAAAAAAAP//9//x//X/9f/4/wAABwANABYAHAAnADIAOABDAEsAVABdAGQAbQBzAH4AhQCKAJEAlQCYAJ4AnwCgAKIAoQCgAJwAmgCXAJIAjwCIAIMAfQB2AG4AZgBeAFQATABGAD4ANQAvACgAIgAaABUADAAIAAQAAQD+//r/9//0//H/7//u/+z/6//r/+r/6v/p/+n/6v/q/+v/7P/u/+//8f/z//X/+P/7//7/AQADAAYACQALABAAEQAUABYAGAAZAB0AHQAfACEAIgAkACUAJQAmACcAJwAoACkAKQAqACsAKwAsACwALQAtAC0ALQAuAC4ALgAuAC4ALgAtAC0ALQAsACwALAAqACkAKQAnACYAJgAkACMAIgAgAB8AHgAcABoAGQAYABYAFAAQAA4ADAAJAAcABQADAAEA//89//7//f/8//v/+v/5//j/9//2//X/9P/z//P/8v/x//D/8P/v/+7/7v/t/+3/7P/s/+v/6//q/+r/6v/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6v/q/+v/6//s/+z/7f/u/+7/7//w//H/8v/z//T/9f/2//f/+P/5//v//P/9/wAAAgADAAUABgAIAAkACwAMAA4AEAARACMACwAEAP//+//4//X/8v/v/+v/6P/l/+L/4P/e/9v/2f/X/9X/1P/S/9H/z//O/83/zf/M/8v/y//K/8r/yv/K/8v/y//L/8z/zf/O/8//0P/S/9P/1f/X/9j/2v/c/97/4f/j/+X/6P/q/+3/8P/z//X/+P/7//7/AQA=";
@@ -275,14 +324,16 @@ game_html = """
275
  console.log('Missed shot');
276
  }
277
  });
278
-
 
279
  restartButton.addEventListener('click', () => {
280
  initGame();
281
  console.log('Game restarted');
282
  });
283
-
284
- initGame(); // Start the game
285
- });
 
286
  </script>
287
  </body>
288
  </html>
@@ -295,7 +346,7 @@ def launch_game():
295
  # Create the Gradio app
296
  with gr.Blocks(title="Bird Shooter Game") as demo:
297
  gr.Markdown("# Bird Shooter Game")
298
- gr.Markdown("Click on the birds to shoot them and earn points! If birds stop appearing, check the browser console (F12) for errors.")
299
  game_output = gr.HTML(label="Game", value=launch_game())
300
 
301
  # Launch the app
 
1
  import gradio as gr
2
 
3
+ # Updated HTML with fixes for continuous bird spawning
4
  game_html = """
5
  <!DOCTYPE html>
6
  <html>
 
23
  <button id="restart-button">Restart</button>
24
  </div>
25
  <script>
26
+ // Wait for the document to be fully loaded
27
+ window.onload = function() {
28
+ console.log("Window loaded");
29
  const gameCanvas = document.getElementById('game-canvas');
30
  const scoreDisplay = document.getElementById('score');
31
  const gameOverDisplay = document.getElementById('game-over');
 
34
  let gameRunning = true;
35
  let birds = [];
36
  let explosions = [];
37
+ let lastBirdSpawn = 0;
38
+ const birdSpawnInterval = 1500; // Spawn a new bird every 1.5 seconds
39
+
40
  function createClouds() {
41
  const cloudCount = 5;
42
  for (let i = 0; i < cloudCount; i++) {
 
59
  gameCanvas.appendChild(cloudPart);
60
  }
61
  }
62
+
63
  class Bird {
64
  constructor() {
65
  this.x = -50;
 
70
  gameCanvas.appendChild(this.element);
71
  console.log('Bird created at x:', this.x, 'y:', this.y);
72
  }
73
+
74
  createBirdElement() {
75
  const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
76
  const body = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
 
80
  body.setAttribute("ry", this.size / 3);
81
  body.setAttribute("fill", this.getRandomColor());
82
  group.appendChild(body);
83
+
84
  const head = document.createElementNS("http://www.w3.org/2000/svg", "circle");
85
  head.setAttribute("cx", this.size / 2);
86
  head.setAttribute("cy", -this.size / 6);
87
  head.setAttribute("r", this.size / 4);
88
  head.setAttribute("fill", this.getRandomColor());
89
  group.appendChild(head);
90
+
91
  const eye = document.createElementNS("http://www.w3.org/2000/svg", "circle");
92
  eye.setAttribute("cx", this.size / 2 + this.size / 8);
93
  eye.setAttribute("cy", -this.size / 6 - this.size / 8);
94
  eye.setAttribute("r", this.size / 10);
95
  eye.setAttribute("fill", "black");
96
  group.appendChild(eye);
97
+
98
  const beak = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
99
  beak.setAttribute("points", `${this.size / 2 + this.size / 4},-${this.size / 6} ${this.size},0 ${this.size / 2 + this.size / 4},${this.size / 10}`);
100
  beak.setAttribute("fill", "orange");
101
  group.appendChild(beak);
102
+
103
  const wing = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
104
  wing.setAttribute("cx", "0");
105
  wing.setAttribute("cy", this.size / 4);
 
108
  wing.setAttribute("fill", this.getRandomColor());
109
  wing.setAttribute("class", "wing");
110
  group.appendChild(wing);
111
+
112
  return group;
113
  }
114
+
115
  getRandomColor() {
116
  const colors = ["#FF5733", "#33FF57", "#3357FF", "#F3FF33", "#FF33F3", "#33FFF3"];
117
  return colors[Math.floor(Math.random() * colors.length)];
118
  }
119
+
120
  update() {
121
  this.x += this.speed;
122
  this.element.setAttribute("transform", `translate(${this.x}, ${this.y})`);
123
+
124
  const wing = this.element.querySelector(".wing");
125
  if (wing) {
126
  const wingAngle = 15 * Math.sin(Date.now() / 100);
127
  wing.setAttribute("transform", `rotate(${wingAngle})`);
128
  }
129
+
130
  if (this.x > 850) {
131
  this.remove();
132
  console.log('Bird removed, remaining birds:', birds.length);
 
134
  }
135
  return true;
136
  }
137
+
138
  remove() {
139
+ if (this.element && this.element.parentNode) {
140
  gameCanvas.removeChild(this.element);
141
  }
142
  }
143
+
144
  checkHit(x, y) {
145
  const birdX = this.x;
146
  const birdY = this.y;
 
148
  return distance < this.size;
149
  }
150
  }
151
+
152
  class Explosion {
153
  constructor(x, y, size) {
154
  this.x = x;
 
160
  gameCanvas.appendChild(this.element);
161
  this.playSound();
162
  }
163
+
164
  createExplosionElement() {
165
  const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
166
  const colors = ["#FF0000", "#FF7700", "#FFFF00"];
167
  const particleCount = 12;
168
+
169
  for (let i = 0; i < particleCount; i++) {
170
  const angle = (i / particleCount) * 2 * Math.PI;
171
  const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
 
177
  circle.setAttribute("data-angle", angle);
178
  group.appendChild(circle);
179
  }
180
+
181
  const center = document.createElementNS("http://www.w3.org/2000/svg", "circle");
182
  center.setAttribute("cx", 0);
183
  center.setAttribute("cy", 0);
 
186
  center.setAttribute("class", "center");
187
  group.appendChild(center);
188
  group.setAttribute("transform", `translate(${this.x}, ${this.y})`);
189
+
190
  return group;
191
  }
192
+
193
  playSound() {
194
  const explosion = new Audio();
195
  explosion.src = "data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=";
196
  explosion.volume = 0.3;
197
  explosion.play();
198
  }
199
+
200
  update() {
201
  this.frame++;
202
  const center = this.element.querySelector(".center");
203
  const sizeMultiplier = 1 + this.frame / 5;
204
  center.setAttribute("r", (this.size / 2) * sizeMultiplier);
205
  center.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
206
+
207
  const particles = this.element.querySelectorAll(".particle");
208
  particles.forEach(particle => {
209
  const angle = parseFloat(particle.getAttribute("data-angle"));
 
215
  particle.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
216
  particle.setAttribute("r", this.size / 8 * (1 - this.frame / this.maxFrames));
217
  });
218
+
219
  if (this.frame >= this.maxFrames) {
220
  this.remove();
221
  return false;
222
  }
223
  return true;
224
  }
225
+
226
  remove() {
227
+ if (this.element && this.element.parentNode) {
228
  gameCanvas.removeChild(this.element);
229
  }
230
  }
231
  }
232
+
233
  function initGame() {
234
  score = 0;
235
  gameRunning = true;
236
  scoreDisplay.textContent = `Score: ${score}`;
237
  gameOverDisplay.style.display = 'none';
238
  restartButton.style.display = 'none';
239
+
240
+ // Clear existing birds and explosions
241
  birds.forEach(bird => bird.remove());
242
  explosions.forEach(explosion => explosion.remove());
243
  birds = [];
244
  explosions = [];
245
+
246
+ // Clear all SVG elements
247
  while (gameCanvas.firstChild) {
248
  gameCanvas.removeChild(gameCanvas.firstChild);
249
  }
250
+
251
  createClouds();
252
  birds.push(new Bird()); // Start with one bird
253
+ lastBirdSpawn = Date.now();
254
  console.log('Game initialized');
255
+
256
+ // Make sure we're starting a fresh game loop
257
+ if (window.gameLoopId) {
258
+ cancelAnimationFrame(window.gameLoopId);
259
+ }
260
  gameLoop();
261
  }
262
+
263
  function gameLoop() {
264
  if (!gameRunning) {
265
  console.log('Game stopped');
266
  return;
267
  }
268
+
269
+ // Use time-based spawning instead of random chance
270
+ const currentTime = Date.now();
271
+ if (currentTime - lastBirdSpawn > birdSpawnInterval) {
272
  birds.push(new Bird());
273
+ lastBirdSpawn = currentTime;
274
+ console.log('New bird spawned, total birds:', birds.length);
275
  }
276
+
277
+ // Update birds
278
  for (let i = birds.length - 1; i >= 0; i--) {
279
  if (!birds[i].update()) {
280
  birds.splice(i, 1);
281
  }
282
  }
283
+
284
+ // Update explosions
285
  for (let i = explosions.length - 1; i >= 0; i--) {
286
  if (!explosions[i].update()) {
287
  explosions.splice(i, 1);
288
  }
289
  }
290
+
291
+ // Store the ID so we can cancel it if needed
292
+ window.gameLoopId = requestAnimationFrame(gameLoop);
293
  }
294
+
295
+ // Set up click handling
296
  gameCanvas.addEventListener('click', (e) => {
297
  if (!gameRunning) return;
298
+
299
  const rect = gameCanvas.getBoundingClientRect();
300
  const x = e.clientX - rect.left;
301
  const y = e.clientY - rect.top;
302
+
303
  let hit = false;
304
  for (let i = birds.length - 1; i >= 0; i--) {
305
  if (birds[i].checkHit(x, y)) {
 
315
  console.log('Bird hit, score:', score);
316
  }
317
  }
318
+
319
  if (!hit) {
320
  const miss = new Audio();
321
  miss.src = "data:audio/wav;base64,UklGRiQDAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YQADAABkAGQAZABkAGQAfACEAJwAsAC8AMgA1ADsAOQA7ADkANQA0AC8AKgAnACMAHQAXABMAEQAPABEADwANAA0ADQALAAsACQAHAAUAAwABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA8AFgAaAB8AIQAnACsAMAAyADMANwA3ADcAMgA0ADAALAApACQAIQAbABYAEQAMAAUAAAAAAAAAAAAAAAAAAAAAAAAAAP//9//x//X/9f/4/wAABwANABYAHAAnADIAOABDAEsAVABdAGQAbQBzAH4AhQCKAJEAlQCYAJ4AnwCgAKIAoQCgAJwAmgCXAJIAjwCIAIMAfQB2AG4AZgBeAFQATABGAD4ANQAvACgAIgAaABUADAAIAAQAAQD+//r/9//0//H/7//u/+z/6//r/+r/6v/p/+n/6v/q/+v/7P/u/+//8f/z//X/+P/7//7/AQADAAYACQALABAAEQAUABYAGAAZAB0AHQAfACEAIgAkACUAJQAmACcAJwAoACkAKQAqACsAKwAsACwALQAtAC0ALQAuAC4ALgAuAC4ALgAtAC0ALQAsACwALAAqACkAKQAnACYAJgAkACMAIgAgAB8AHgAcABoAGQAYABYAFAAQAA4ADAAJAAcABQADAAEA//89//7//f/8//v/+v/5//j/9//2//X/9P/z//P/8v/x//D/8P/v/+7/7v/t/+3/7P/s/+v/6//q/+r/6v/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6v/q/+v/6//s/+z/7f/u/+7/7//w//H/8v/z//T/9f/2//f/+P/5//v//P/9/wAAAgADAAUABgAIAAkACwAMAA4AEAARACMACwAEAP//+//4//X/8v/v/+v/6P/l/+L/4P/e/9v/2f/X/9X/1P/S/9H/z//O/83/zf/M/8v/y//K/8r/yv/K/8v/y//L/8z/zf/O/8//0P/S/9P/1f/X/9j/2v/c/97/4f/j/+X/6P/q/+3/8P/z//X/+P/7//7/AQA=";
 
324
  console.log('Missed shot');
325
  }
326
  });
327
+
328
+ // Set up restart button
329
  restartButton.addEventListener('click', () => {
330
  initGame();
331
  console.log('Game restarted');
332
  });
333
+
334
+ // Start the game
335
+ initGame();
336
+ };
337
  </script>
338
  </body>
339
  </html>
 
346
  # Create the Gradio app
347
  with gr.Blocks(title="Bird Shooter Game") as demo:
348
  gr.Markdown("# Bird Shooter Game")
349
+ gr.Markdown("Click on the birds to shoot them and earn points! Birds will continuously fly across the screen.")
350
  game_output = gr.HTML(label="Game", value=launch_game())
351
 
352
  # Launch the app