sagar007 commited on
Commit
ef2f59c
·
verified ·
1 Parent(s): eeed6b8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +242 -224
app.py CHANGED
@@ -1,6 +1,6 @@
1
  import gradio as gr
2
 
3
- # The HTML code for the Bird Shooter game (minified to fit as a string)
4
  game_html = """
5
  <!DOCTYPE html>
6
  <html>
@@ -23,244 +23,262 @@ game_html = """
23
  <button id="restart-button">Restart</button>
24
  </div>
25
  <script>
26
- const gameCanvas = document.getElementById('game-canvas');
27
- const scoreDisplay = document.getElementById('score');
28
- const gameOverDisplay = document.getElementById('game-over');
29
- const restartButton = document.getElementById('restart-button');
30
- let score = 0;
31
- let gameRunning = true;
32
- let birds = [];
33
- let explosions = [];
34
- function createClouds() {
35
- const cloudCount = 5;
36
- for (let i = 0; i < cloudCount; i++) {
37
- const cloud = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
38
- cloud.setAttribute("cx", Math.random() * 800);
39
- cloud.setAttribute("cy", 50 + Math.random() * 100);
40
- cloud.setAttribute("rx", 50 + Math.random() * 50);
41
- cloud.setAttribute("ry", 20 + Math.random() * 20);
42
- cloud.setAttribute("fill", "white");
43
- cloud.setAttribute("opacity", "0.8");
44
- cloud.classList.add("cloud");
45
- gameCanvas.appendChild(cloud);
46
- const cloudPart = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
47
- cloudPart.setAttribute("cx", parseFloat(cloud.getAttribute("cx")) + 30);
48
- cloudPart.setAttribute("cy", parseFloat(cloud.getAttribute("cy")) - 5);
49
- cloudPart.setAttribute("rx", 30);
50
- cloudPart.setAttribute("ry", 15);
51
- cloudPart.setAttribute("fill", "white");
52
- cloudPart.setAttribute("opacity", "0.8");
53
- gameCanvas.appendChild(cloudPart);
54
- }
55
- }
56
- class Bird {
57
- constructor() {
58
- this.x = -50;
59
- this.y = 100 + Math.random() * 300;
60
- this.speed = 2 + Math.random() * 3;
61
- this.size = 30 + Math.random() * 20;
62
- this.element = this.createBirdElement();
63
- gameCanvas.appendChild(this.element);
64
- }
65
- createBirdElement() {
66
- const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
67
- const body = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
68
- body.setAttribute("cx", "0");
69
- body.setAttribute("cy", "0");
70
- body.setAttribute("rx", this.size / 2);
71
- body.setAttribute("ry", this.size / 3);
72
- body.setAttribute("fill", this.getRandomColor());
73
- group.appendChild(body);
74
- const head = document.createElementNS("http://www.w3.org/2000/svg", "circle");
75
- head.setAttribute("cx", this.size / 2);
76
- head.setAttribute("cy", -this.size / 6);
77
- head.setAttribute("r", this.size / 4);
78
- head.setAttribute("fill", this.getRandomColor());
79
- group.appendChild(head);
80
- const eye = document.createElementNS("http://www.w3.org/2000/svg", "circle");
81
- eye.setAttribute("cx", this.size / 2 + this.size / 8);
82
- eye.setAttribute("cy", -this.size / 6 - this.size / 8);
83
- eye.setAttribute("r", this.size / 10);
84
- eye.setAttribute("fill", "black");
85
- group.appendChild(eye);
86
- const beak = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
87
- beak.setAttribute("points", `${this.size / 2 + this.size / 4},-${this.size / 6} ${this.size},0 ${this.size / 2 + this.size / 4},${this.size / 10}`);
88
- beak.setAttribute("fill", "orange");
89
- group.appendChild(beak);
90
- const wing = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
91
- wing.setAttribute("cx", "0");
92
- wing.setAttribute("cy", this.size / 4);
93
- wing.setAttribute("rx", this.size / 3);
94
- wing.setAttribute("ry", this.size / 6);
95
- wing.setAttribute("fill", this.getRandomColor());
96
- wing.setAttribute("class", "wing");
97
- group.appendChild(wing);
98
- return group;
99
- }
100
- getRandomColor() {
101
- const colors = ["#FF5733", "#33FF57", "#3357FF", "#F3FF33", "#FF33F3", "#33FFF3"];
102
- return colors[Math.floor(Math.random() * colors.length)];
103
  }
104
- update() {
105
- this.x += this.speed;
106
- this.element.setAttribute("transform", `translate(${this.x}, ${this.y})`);
107
- const wing = this.element.querySelector(".wing");
108
- if (wing) {
109
- const wingAngle = 15 * Math.sin(Date.now() / 100);
110
- wing.setAttribute("transform", `rotate(${wingAngle})`);
 
 
111
  }
112
- if (this.x > 850) {
113
- this.remove();
114
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
- return true;
117
- }
118
- remove() {
119
- if (this.element.parentNode) {
120
- gameCanvas.removeChild(this.element);
121
  }
122
- }
123
- checkHit(x, y) {
124
- const birdX = this.x;
125
- const birdY = this.y;
126
- const distance = Math.sqrt(Math.pow(birdX - x, 2) + Math.pow(birdY - y, 2));
127
- return distance < this.size;
128
- }
129
- }
130
- class Explosion {
131
- constructor(x, y, size) {
132
- this.x = x;
133
- this.y = y;
134
- this.size = size;
135
- this.frame = 0;
136
- this.maxFrames = 20;
137
- this.element = this.createExplosionElement();
138
- gameCanvas.appendChild(this.element);
139
- this.playSound();
140
- }
141
- createExplosionElement() {
142
- const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
143
- const colors = ["#FF0000", "#FF7700", "#FFFF00"];
144
- const particleCount = 12;
145
- for (let i = 0; i < particleCount; i++) {
146
- const angle = (i / particleCount) * 2 * Math.PI;
147
- const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
148
- circle.setAttribute("cx", Math.cos(angle) * (this.size / 3));
149
- circle.setAttribute("cy", Math.sin(angle) * (this.size / 3));
150
- circle.setAttribute("r", this.size / 8);
151
- circle.setAttribute("fill", colors[Math.floor(Math.random() * colors.length)]);
152
- circle.setAttribute("class", "particle");
153
- circle.setAttribute("data-angle", angle);
154
- group.appendChild(circle);
155
  }
156
- const center = document.createElementNS("http://www.w3.org/2000/svg", "circle");
157
- center.setAttribute("cx", 0);
158
- center.setAttribute("cy", 0);
159
- center.setAttribute("r", this.size / 2);
160
- center.setAttribute("fill", "#FF0000");
161
- center.setAttribute("class", "center");
162
- group.appendChild(center);
163
- group.setAttribute("transform", `translate(${this.x}, ${this.y})`);
164
- return group;
165
- }
166
- playSound() {
167
- const explosion = new Audio();
168
- 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=";
169
- explosion.volume = 0.3;
170
- explosion.play();
171
- }
172
- update() {
173
- this.frame++;
174
- const center = this.element.querySelector(".center");
175
- const sizeMultiplier = 1 + this.frame / 5;
176
- center.setAttribute("r", (this.size / 2) * sizeMultiplier);
177
- center.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
178
- const particles = this.element.querySelectorAll(".particle");
179
- particles.forEach(particle => {
180
- const angle = parseFloat(particle.getAttribute("data-angle"));
181
- const distance = (this.size / 3) + (this.frame * 2);
182
- const x = Math.cos(angle) * distance;
183
- const y = Math.sin(angle) * distance;
184
- particle.setAttribute("cx", x);
185
- particle.setAttribute("cy", y);
186
- particle.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
187
- particle.setAttribute("r", this.size / 8 * (1 - this.frame / this.maxFrames));
188
- });
189
- if (this.frame >= this.maxFrames) {
190
- this.remove();
191
- return false;
192
  }
193
- return true;
194
- }
195
- remove() {
196
- if (this.element.parentNode) {
197
- gameCanvas.removeChild(this.element);
198
  }
199
  }
200
- }
201
- function initGame() {
202
- score = 0;
203
- gameRunning = true;
204
- scoreDisplay.textContent = `Score: ${score}`;
205
- gameOverDisplay.style.display = 'none';
206
- restartButton.style.display = 'none';
207
- birds.forEach(bird => bird.remove());
208
- explosions.forEach(explosion => explosion.remove());
209
- birds = [];
210
- explosions = [];
211
- while (gameCanvas.firstChild) {
212
- gameCanvas.removeChild(gameCanvas.firstChild);
213
- }
214
- createClouds();
215
- gameLoop();
216
- }
217
- function gameLoop() {
218
- if (!gameRunning) return;
219
- if (Math.random() < 0.02) {
220
- birds.push(new Bird());
221
- }
222
- for (let i = birds.length - 1; i >= 0; i--) {
223
- if (!birds[i].update()) {
224
- birds.splice(i, 1);
225
  }
226
- }
227
- for (let i = explosions.length - 1; i >= 0; i--) {
228
- if (!explosions[i].update()) {
229
- explosions.splice(i, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  }
231
  }
232
- requestAnimationFrame(gameLoop);
233
- }
234
- gameCanvas.addEventListener('click', (e) => {
235
- if (!gameRunning) return;
236
- const rect = gameCanvas.getBoundingClientRect();
237
- const x = e.clientX - rect.left;
238
- const y = e.clientY - rect.top;
239
- let hit = false;
240
- for (let i = birds.length - 1; i >= 0; i--) {
241
- if (birds[i].checkHit(x, y)) {
242
- const birdX = birds[i].x;
243
- const birdY = birds[i].y;
244
- const birdSize = birds[i].size;
245
- birds[i].remove();
246
- birds.splice(i, 1);
247
- explosions.push(new Explosion(birdX, birdY, birdSize * 2));
248
- score += 10;
249
- scoreDisplay.textContent = `Score: ${score}`;
250
- hit = true;
251
  }
 
 
 
252
  }
253
- if (!hit) {
254
- const miss = new Audio();
255
- 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=";
256
- miss.volume = 0.2;
257
- miss.play();
 
 
 
 
 
 
 
 
 
 
 
 
258
  }
259
- });
260
- restartButton.addEventListener('click', () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  initGame();
262
  });
263
- initGame();
264
  </script>
265
  </body>
266
  </html>
@@ -273,7 +291,7 @@ def launch_game():
273
  # Create the Gradio app
274
  with gr.Blocks(title="Bird Shooter Game") as demo:
275
  gr.Markdown("# Bird Shooter Game")
276
- gr.Markdown("Click on the birds to shoot them and earn points!")
277
  game_output = gr.HTML(label="Game", value=launch_game())
278
 
279
  # Launch the app
 
1
  import gradio as gr
2
 
3
+ # Updated HTML with explicit initialization to ensure the game starts
4
  game_html = """
5
  <!DOCTYPE html>
6
  <html>
 
23
  <button id="restart-button">Restart</button>
24
  </div>
25
  <script>
26
+ // Ensure DOM is fully loaded before starting the game
27
+ document.addEventListener('DOMContentLoaded', () => {
28
+ const gameCanvas = document.getElementById('game-canvas');
29
+ const scoreDisplay = document.getElementById('score');
30
+ const gameOverDisplay = document.getElementById('game-over');
31
+ const restartButton = document.getElementById('restart-button');
32
+ let score = 0;
33
+ let gameRunning = true;
34
+ let birds = [];
35
+ let explosions = [];
36
+
37
+ function createClouds() {
38
+ const cloudCount = 5;
39
+ for (let i = 0; i < cloudCount; i++) {
40
+ const cloud = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
41
+ cloud.setAttribute("cx", Math.random() * 800);
42
+ cloud.setAttribute("cy", 50 + Math.random() * 100);
43
+ cloud.setAttribute("rx", 50 + Math.random() * 50);
44
+ cloud.setAttribute("ry", 20 + Math.random() * 20);
45
+ cloud.setAttribute("fill", "white");
46
+ cloud.setAttribute("opacity", "0.8");
47
+ cloud.classList.add("cloud");
48
+ gameCanvas.appendChild(cloud);
49
+ const cloudPart = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
50
+ cloudPart.setAttribute("cx", parseFloat(cloud.getAttribute("cx")) + 30);
51
+ cloudPart.setAttribute("cy", parseFloat(cloud.getAttribute("cy")) - 5);
52
+ cloudPart.setAttribute("rx", 30);
53
+ cloudPart.setAttribute("ry", 15);
54
+ cloudPart.setAttribute("fill", "white");
55
+ cloudPart.setAttribute("opacity", "0.8");
56
+ gameCanvas.appendChild(cloudPart);
57
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
+
60
+ class Bird {
61
+ constructor() {
62
+ this.x = -50;
63
+ this.y = 100 + Math.random() * 300;
64
+ this.speed = 2 + Math.random() * 3;
65
+ this.size = 30 + Math.random() * 20;
66
+ this.element = this.createBirdElement();
67
+ gameCanvas.appendChild(this.element);
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");
72
+ body.setAttribute("cx", "0");
73
+ body.setAttribute("cy", "0");
74
+ body.setAttribute("rx", this.size / 2);
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);
97
+ wing.setAttribute("rx", this.size / 3);
98
+ wing.setAttribute("ry", this.size / 6);
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
+ if (birds.length === 0 && gameRunning) {
119
+ gameOverDisplay.style.display = 'block';
120
+ restartButton.style.display = 'block';
121
+ gameRunning = false;
122
+ }
123
+ return false;
124
+ }
125
+ return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
+ remove() {
128
+ if (this.element.parentNode) {
129
+ gameCanvas.removeChild(this.element);
130
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
+ checkHit(x, y) {
133
+ const birdX = this.x;
134
+ const birdY = this.y;
135
+ const distance = Math.sqrt(Math.pow(birdX - x, 2) + Math.pow(birdY - y, 2));
136
+ return distance < this.size;
137
  }
138
  }
139
+
140
+ class Explosion {
141
+ constructor(x, y, size) {
142
+ this.x = x;
143
+ this.y = y;
144
+ this.size = size;
145
+ this.frame = 0;
146
+ this.maxFrames = 20;
147
+ this.element = this.createExplosionElement();
148
+ gameCanvas.appendChild(this.element);
149
+ this.playSound();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
+ createExplosionElement() {
152
+ const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
153
+ const colors = ["#FF0000", "#FF7700", "#FFFF00"];
154
+ const particleCount = 12;
155
+ for (let i = 0; i < particleCount; i++) {
156
+ const angle = (i / particleCount) * 2 * Math.PI;
157
+ const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
158
+ circle.setAttribute("cx", Math.cos(angle) * (this.size / 3));
159
+ circle.setAttribute("cy", Math.sin(angle) * (this.size / 3));
160
+ circle.setAttribute("r", this.size / 8);
161
+ circle.setAttribute("fill", colors[Math.floor(Math.random() * colors.length)]);
162
+ circle.setAttribute("class", "particle");
163
+ circle.setAttribute("data-angle", angle);
164
+ group.appendChild(circle);
165
+ }
166
+ const center = document.createElementNS("http://www.w3.org/2000/svg", "circle");
167
+ center.setAttribute("cx", 0);
168
+ center.setAttribute("cy", 0);
169
+ center.setAttribute("r", this.size / 2);
170
+ center.setAttribute("fill", "#FF0000");
171
+ center.setAttribute("class", "center");
172
+ group.appendChild(center);
173
+ group.setAttribute("transform", `translate(${this.x}, ${this.y})`);
174
+ return group;
175
+ }
176
+ playSound() {
177
+ const explosion = new Audio();
178
+ 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=";
179
+ explosion.volume = 0.3;
180
+ explosion.play();
181
+ }
182
+ update() {
183
+ this.frame++;
184
+ const center = this.element.querySelector(".center");
185
+ const sizeMultiplier = 1 + this.frame / 5;
186
+ center.setAttribute("r", (this.size / 2) * sizeMultiplier);
187
+ center.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
188
+ const particles = this.element.querySelectorAll(".particle");
189
+ particles.forEach(particle => {
190
+ const angle = parseFloat(particle.getAttribute("data-angle"));
191
+ const distance = (this.size / 3) + (this.frame * 2);
192
+ const x = Math.cos(angle) * distance;
193
+ const y = Math.sin(angle) * distance;
194
+ particle.setAttribute("cx", x);
195
+ particle.setAttribute("cy", y);
196
+ particle.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
197
+ particle.setAttribute("r", this.size / 8 * (1 - this.frame / this.maxFrames));
198
+ });
199
+ if (this.frame >= this.maxFrames) {
200
+ this.remove();
201
+ return false;
202
+ }
203
+ return true;
204
+ }
205
+ remove() {
206
+ if (this.element.parentNode) {
207
+ gameCanvas.removeChild(this.element);
208
+ }
209
  }
210
  }
211
+
212
+ function initGame() {
213
+ score = 0;
214
+ gameRunning = true;
215
+ scoreDisplay.textContent = `Score: ${score}`;
216
+ gameOverDisplay.style.display = 'none';
217
+ restartButton.style.display = 'none';
218
+ birds.forEach(bird => bird.remove());
219
+ explosions.forEach(explosion => explosion.remove());
220
+ birds = [];
221
+ explosions = [];
222
+ while (gameCanvas.firstChild) {
223
+ gameCanvas.removeChild(gameCanvas.firstChild);
 
 
 
 
 
 
224
  }
225
+ createClouds();
226
+ birds.push(new Bird()); // Start with one bird to ensure something happens
227
+ gameLoop();
228
  }
229
+
230
+ function gameLoop() {
231
+ if (!gameRunning) return;
232
+ if (Math.random() < 0.02) {
233
+ birds.push(new Bird());
234
+ }
235
+ for (let i = birds.length - 1; i >= 0; i--) {
236
+ if (!birds[i].update()) {
237
+ birds.splice(i, 1);
238
+ }
239
+ }
240
+ for (let i = explosions.length - 1; i >= 0; i--) {
241
+ if (!explosions[i].update()) {
242
+ explosions.splice(i, 1);
243
+ }
244
+ }
245
+ requestAnimationFrame(gameLoop);
246
  }
247
+
248
+ gameCanvas.addEventListener('click', (e) => {
249
+ if (!gameRunning) return;
250
+ const rect = gameCanvas.getBoundingClientRect();
251
+ const x = e.clientX - rect.left;
252
+ const y = e.clientY - rect.top;
253
+ let hit = false;
254
+ for (let i = birds.length - 1; i >= 0; i--) {
255
+ if (birds[i].checkHit(x, y)) {
256
+ const birdX = birds[i].x;
257
+ const birdY = birds[i].y;
258
+ const birdSize = birds[i].size;
259
+ birds[i].remove();
260
+ birds.splice(i, 1);
261
+ explosions.push(new Explosion(birdX, birdY, birdSize * 2));
262
+ score += 10;
263
+ scoreDisplay.textContent = `Score: ${score}`;
264
+ hit = true;
265
+ }
266
+ }
267
+ if (!hit) {
268
+ const miss = new Audio();
269
+ 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=";
270
+ miss.volume = 0.2;
271
+ miss.play();
272
+ }
273
+ });
274
+
275
+ restartButton.addEventListener('click', () => {
276
+ initGame();
277
+ });
278
+
279
+ // Start the game explicitly
280
  initGame();
281
  });
 
282
  </script>
283
  </body>
284
  </html>
 
291
  # Create the Gradio app
292
  with gr.Blocks(title="Bird Shooter Game") as demo:
293
  gr.Markdown("# Bird Shooter Game")
294
+ gr.Markdown("Click on the birds to shoot them and earn points! If nothing happens, try refreshing the page.")
295
  game_output = gr.HTML(label="Game", value=launch_game())
296
 
297
  # Launch the app