akhaliq HF staff commited on
Commit
b9232bd
·
verified ·
1 Parent(s): bb13fe7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +263 -217
app.py CHANGED
@@ -4,232 +4,278 @@ demo = gr.Blocks()
4
 
5
  with demo:
6
  gr.HTML("""<!DOCTYPE html>
7
- <html>
8
- <head>
9
- <title>Maze Game Demo</title>
10
- <style>
11
- body { margin: 0; overflow: hidden; }
12
- #debug {
13
- position: absolute;
14
- top: 10px;
15
- left: 10px;
16
- color: white;
17
- background: rgba(0, 0, 0, 0.7);
18
- padding: 5px;
19
- font-family: monospace;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
- </style>
22
- </head>
23
- <body>
24
- <div id="debug"></div>
25
- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
26
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script>
27
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
28
- <script>
29
- // Scene setup
30
- const scene = new THREE.Scene();
31
- const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
32
- const renderer = new THREE.WebGLRenderer();
33
- renderer.setSize(window.innerWidth, window.innerHeight);
34
- document.body.appendChild(renderer.domElement);
35
-
36
- // Lighting
37
- const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.6);
38
- scene.add(hemiLight);
39
- const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
40
- dirLight.position.set(0, 20, 10);
41
- scene.add(dirLight);
42
-
43
- // OrbitControls
44
- const controls = new THREE.OrbitControls(camera, renderer.domElement);
45
- controls.enableDamping = true;
46
-
47
- // Maze generation
48
- const gridSize = 16;
49
- const cellSize = 4;
50
- const maze = [];
51
- const walls = [];
52
-
53
- function createTexture(width, height, type) {
54
- const canvas = document.createElement('canvas');
55
- canvas.width = width;
56
- canvas.height = height;
57
- const ctx = canvas.getContext('2d');
58
-
59
- if (type === 'floor') {
60
- ctx.fillStyle = '#8B4513';
61
- ctx.fillRect(0, 0, width, height);
62
- ctx.strokeStyle = '#654321';
63
- ctx.lineWidth = 2;
64
- ctx.strokeRect(0, 0, width, height);
65
  } else {
66
- ctx.fillStyle = '#666666';
67
- ctx.fillRect(0, 0, width, height);
68
- for (let i = 0; i < 10; i++) {
69
- ctx.fillStyle = `rgba(0, 0, 0, ${Math.random() * 0.3})`;
70
- ctx.fillRect(
71
- Math.random() * width,
72
- Math.random() * height,
73
- Math.random() * width/4,
74
- Math.random() * height/4
75
- );
76
- }
77
  }
78
- return new THREE.CanvasTexture(canvas);
79
  }
80
-
81
- const floorTexture = createTexture(256, 256, 'floor');
82
- const wallTexture = createTexture(256, 256, 'wall');
83
-
84
- // Generate maze
85
- for (let x = 0; x < gridSize; x++) {
86
- maze[x] = [];
87
- for (let z = 0; z < gridSize; z++) {
88
- const isBoundary = x === 0 || x === gridSize - 1 || z === 0 || z === gridSize - 1;
89
- const isCenter = x >= 6 && x <= 9 && z >= 6 && z <= 9;
90
- const isWall = isBoundary || (!isCenter && Math.random() < 0.15);
91
- maze[x][z] = isWall ? 1 : 0;
92
-
93
- if (isWall) {
94
- const wallGeometry = new THREE.BoxGeometry(cellSize, cellSize, cellSize);
95
- const wallMaterial = new THREE.MeshPhongMaterial({ map: wallTexture });
96
- const wall = new THREE.Mesh(wallGeometry, wallMaterial);
97
- wall.position.set(x * cellSize, cellSize/2, z * cellSize);
98
- scene.add(wall);
99
- wall.boundingBox = new THREE.Box3().setFromObject(wall);
100
- walls.push(wall);
101
- }
 
102
  }
103
  }
104
-
105
- // Floor
106
- const floorGeometry = new THREE.PlaneGeometry(gridSize * cellSize, gridSize * cellSize);
107
- const floorMaterial = new THREE.MeshPhongMaterial({ map: floorTexture });
108
- const floor = new THREE.Mesh(floorGeometry, floorMaterial);
109
- floor.rotation.x = -Math.PI / 2;
110
- scene.add(floor);
111
-
112
- // Soldier setup
113
- const loader = new THREE.GLTFLoader();
114
- const soldiers = [];
115
- const mixers = [];
116
-
117
- function createSoldier(team, startX, startZ) {
118
- loader.load('https://threejs.org/examples/models/gltf/Soldier.glb', (gltf) => {
119
- const soldier = gltf.scene;
120
- soldier.scale.set(2, 2, 2);
121
- soldier.position.set(startX, 0, startZ);
122
- soldier.team = team;
123
- soldier.collisionRadius = 1;
124
- soldier.speed = 0.1;
125
- scene.add(soldier);
126
- soldiers.push(soldier);
127
-
128
- const mixer = new THREE.AnimationMixer(soldier);
129
- mixers.push(mixer);
130
-
131
- const idleAction = mixer.clipAction(gltf.animations[0]);
132
- const runAction = mixer.clipAction(gltf.animations[3]);
133
-
134
- soldier.actions = { idle: idleAction, run: runAction };
135
- idleAction.play();
136
- });
137
- }
138
-
139
- // Create two teams
140
- createSoldier(1, 28, 28); // Team 1
141
- createSoldier(2, 36, 36); // Team 2
142
-
143
- camera.position.set(32, 20, 32);
144
-
145
- // Movement controls
146
- const keys = { w: false, a: false, s: false, d: false };
147
- document.addEventListener('keydown', (e) => {
148
- if (e.key in keys) keys[e.key] = true;
149
- });
150
- document.addEventListener('keyup', (e) => {
151
- if (e.key in keys) keys[e.key] = false;
152
- });
153
-
154
- function checkCollision(newPosition, soldier) {
155
- const soldierBox = new THREE.Sphere(newPosition, soldier.collisionRadius);
156
- for (const wall of walls) {
157
- if (soldierBox.intersectsBox(wall.boundingBox)) {
158
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
  }
161
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
-
164
- // Animation loop
165
- const clock = new THREE.Clock();
166
- function animate() {
167
- requestAnimationFrame(animate);
168
- const delta = clock.getDelta();
169
-
170
- soldiers.forEach((soldier, index) => {
171
- if (!soldier) return;
172
-
173
- const moveDirection = new THREE.Vector3();
174
- if (index === 0) { // Only control first soldier for demo
175
- const camForward = new THREE.Vector3();
176
- camera.getWorldDirection(camForward);
177
- camForward.y = 0;
178
- camForward.normalize();
179
- const camLeft = new THREE.Vector3(-camForward.z, 0, camForward.x);
180
-
181
- if (keys.w) moveDirection.add(camForward);
182
- if (keys.s) moveDirection.sub(camForward);
183
- if (keys.a) moveDirection.add(camLeft);
184
- if (keys.d) moveDirection.sub(camLeft);
185
- }
186
-
187
- if (moveDirection.length() > 0) {
188
- moveDirection.normalize();
189
- const newPosition = soldier.position.clone()
190
- .add(moveDirection.multiplyScalar(soldier.speed));
191
-
192
- if (!checkCollision(newPosition, soldier)) {
193
- soldier.position.copy(newPosition);
194
- const angle = Math.atan2(moveDirection.x, moveDirection.z);
195
- soldier.rotation.y = angle + Math.PI;
196
-
197
- soldier.actions.idle.fadeOut(0.2);
198
- soldier.actions.run.fadeIn(0.2);
199
- }
200
- } else {
201
- soldier.actions.run.fadeOut(0.2);
202
- soldier.actions.idle.fadeIn(0.2);
203
- }
204
-
205
- if (index === 0) {
206
- controls.target.copy(soldier.position);
207
- controls.update();
208
-
209
- // Update debug overlay
210
- document.getElementById('debug').innerHTML = `
211
- Position: ${soldier.position.x.toFixed(2)},
212
- ${soldier.position.y.toFixed(2)},
213
- ${soldier.position.z.toFixed(2)}<br>
214
- Rotation: ${(soldier.rotation.y * 180 / Math.PI).toFixed(2)}°
215
- `;
216
- }
217
- });
218
-
219
- mixers.forEach(mixer => mixer.update(delta));
220
- renderer.render(scene, camera);
221
  }
222
-
223
- // Responsive design
224
- window.addEventListener('resize', () => {
225
- camera.aspect = window.innerWidth / window.innerHeight;
226
- camera.updateProjectionMatrix();
227
- renderer.setSize(window.innerWidth, window.innerHeight);
228
- });
229
-
230
- animate();
231
- </script>
232
- </body>
233
- </html>""")
 
 
 
234
 
235
  demo.launch()
 
4
 
5
  with demo:
6
  gr.HTML("""<!DOCTYPE html>
7
+ <html lang="en">
8
+ <head>
9
+ <meta charset="UTF-8">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
11
+ <title>3D Maze Game Demo</title>
12
+ <style>
13
+ body {
14
+ margin: 0;
15
+ overflow: hidden;
16
+ }
17
+ #container {
18
+ position: relative;
19
+ }
20
+ #debug {
21
+ position: absolute;
22
+ top: 10px;
23
+ left: 10px;
24
+ color: white;
25
+ background: rgba(0, 0, 0, 0.5);
26
+ padding: 10px;
27
+ font-family: Arial, sans-serif;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body>
32
+ <div id="container"></div>
33
+ <div id="debug">
34
+ <p>Position: <span id="position"></span></p>
35
+ <p>Rotation: <span id="rotation"></span></p>
36
+ </div>
37
+
38
+ <!-- Libraries from CDNs -->
39
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
40
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script>
41
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
42
+
43
+ <script>
44
+ // Scene Setup
45
+ const scene = new THREE.Scene();
46
+ const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
47
+ const renderer = new THREE.WebGLRenderer();
48
+ renderer.setSize(window.innerWidth, window.innerHeight);
49
+ document.getElementById('container').appendChild(renderer.domElement);
50
+
51
+ // Lighting
52
+ const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
53
+ hemiLight.position.set(0, 20, 0);
54
+ scene.add(hemiLight);
55
+ const dirLight = new THREE.DirectionalLight(0xffffff);
56
+ dirLight.position.set(0, 20, 10);
57
+ scene.add(dirLight);
58
+
59
+ // Floor Texture
60
+ function createFloorTexture() {
61
+ const canvas = document.createElement('canvas');
62
+ canvas.width = 256;
63
+ canvas.height = 256;
64
+ const context = canvas.getContext('2d');
65
+ context.fillStyle = '#8B4513'; // Brown tone
66
+ context.fillRect(0, 0, 256, 256);
67
+ context.strokeStyle = '#FFFFFF';
68
+ context.lineWidth = 2;
69
+ for (let i = 0; i <= 16; i++) {
70
+ const pos = i * 16;
71
+ context.beginPath();
72
+ context.moveTo(pos, 0);
73
+ context.lineTo(pos, 256);
74
+ context.stroke();
75
+ context.beginPath();
76
+ context.moveTo(0, pos);
77
+ context.lineTo(256, pos);
78
+ context.stroke();
79
  }
80
+ const texture = new THREE.CanvasTexture(canvas);
81
+ texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
82
+ texture.repeat.set(16, 16);
83
+ return texture;
84
+ }
85
+
86
+ // Wall Texture
87
+ function createWallTexture() {
88
+ const canvas = document.createElement('canvas');
89
+ canvas.width = 64;
90
+ canvas.height = 64;
91
+ const context = canvas.getContext('2d');
92
+ context.fillStyle = '#808080'; // Gray base
93
+ context.fillRect(0, 0, 64, 64);
94
+ context.fillStyle = '#A0A0A0';
95
+ for (let i = 0; i < 100; i++) {
96
+ const x = Math.random() * 64;
97
+ const y = Math.random() * 64;
98
+ context.fillRect(x, y, 2, 2);
99
+ }
100
+ return new THREE.CanvasTexture(canvas);
101
+ }
102
+
103
+ // Floor
104
+ const floorTexture = createFloorTexture();
105
+ const floorGeometry = new THREE.PlaneGeometry(64, 64);
106
+ const floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture });
107
+ const floor = new THREE.Mesh(floorGeometry, floorMaterial);
108
+ floor.rotation.x = -Math.PI / 2;
109
+ scene.add(floor);
110
+
111
+ // Maze Generation
112
+ const gridSize = 16;
113
+ const cellSize = 4;
114
+ const maze = [];
115
+ for (let i = 0; i < gridSize; i++) {
116
+ maze[i] = [];
117
+ for (let j = 0; j < gridSize; j++) {
118
+ if (i === 0 || i === gridSize - 1 || j === 0 || j === gridSize - 1) {
119
+ maze[i][j] = 1; // Walls on boundaries
120
+ } else if (i >= 6 && i <= 9 && j >= 6 && j <= 9) {
121
+ maze[i][j] = 0; // Central open area
 
 
122
  } else {
123
+ maze[i][j] = Math.random() < 0.15 ? 1 : 0; // 15% chance of wall
 
 
 
 
 
 
 
 
 
 
124
  }
 
125
  }
126
+ }
127
+
128
+ // Walls and Collision Bounds
129
+ const wallTexture = createWallTexture();
130
+ const wallGeometry = new THREE.BoxGeometry(cellSize, cellSize, cellSize);
131
+ const wallMaterial = new THREE.MeshBasicMaterial({ map: wallTexture });
132
+ const walls = [];
133
+ const wallBounds = [];
134
+ for (let i = 0; i < gridSize; i++) {
135
+ for (let j = 0; j < gridSize; j++) {
136
+ if (maze[i][j] === 1) {
137
+ const wall = new THREE.Mesh(wallGeometry, wallMaterial);
138
+ const x = (j - 7.5) * cellSize;
139
+ const z = (i - 7.5) * cellSize;
140
+ wall.position.set(x, cellSize / 2, z);
141
+ scene.add(wall);
142
+ walls.push(wall);
143
+ wallBounds.push({
144
+ minX: x - cellSize / 2,
145
+ maxX: x + cellSize / 2,
146
+ minZ: z - cellSize / 2,
147
+ maxZ: z + cellSize / 2
148
+ });
149
  }
150
  }
151
+ }
152
+
153
+ // Soldier Setup
154
+ const loader = new THREE.GLTFLoader();
155
+ let soldier, mixer, idleAction, runAction, activeAction;
156
+ loader.load(
157
+ 'https://threejs.org/examples/models/gltf/Soldier.glb',
158
+ (gltf) => {
159
+ soldier = gltf.scene;
160
+ soldier.scale.set(2, 2, 2);
161
+ soldier.position.set(0, 0, 0);
162
+ scene.add(soldier);
163
+
164
+ mixer = new THREE.AnimationMixer(soldier);
165
+ const animations = gltf.animations;
166
+ idleAction = mixer.clipAction(THREE.AnimationClip.findByName(animations, 'Idle'));
167
+ runAction = mixer.clipAction(THREE.AnimationClip.findByName(animations, 'Run'));
168
+ activeAction = idleAction;
169
+ activeAction.play();
170
+ },
171
+ undefined,
172
+ (error) => console.error('Error loading soldier:', error)
173
+ );
174
+
175
+ // Camera and Controls
176
+ camera.position.set(0, 5, 10);
177
+ const controls = new THREE.OrbitControls(camera, renderer.domElement);
178
+ controls.target.set(0, 0, 0);
179
+ controls.update();
180
+
181
+ // Movement Controls
182
+ const keys = new Set();
183
+ window.addEventListener('keydown', (e) => keys.add(e.key.toLowerCase()));
184
+ window.addEventListener('keyup', (e) => keys.delete(e.key.toLowerCase()));
185
+
186
+ const moveSpeed = 10; // Units per second
187
+ const collisionRadius = 0.5;
188
+
189
+ function updateSoldier(delta) {
190
+ if (!soldier) return;
191
+
192
+ const forward = new THREE.Vector3();
193
+ camera.getWorldDirection(forward);
194
+ forward.y = 0;
195
+ forward.normalize();
196
+
197
+ const right = new THREE.Vector3();
198
+ right.crossVectors(forward, new THREE.Vector3(0, 1, 0));
199
+
200
+ const moveDirection = new THREE.Vector3();
201
+ if (keys.has('w')) moveDirection.add(forward);
202
+ if (keys.has('s')) moveDirection.add(forward.clone().negate());
203
+ if (keys.has('a')) moveDirection.add(right.clone().negate());
204
+ if (keys.has('d')) moveDirection.add(right);
205
+
206
+ if (moveDirection.lengthSq() > 0) {
207
+ moveDirection.normalize();
208
+ const newPosition = soldier.position.clone().add(
209
+ moveDirection.multiplyScalar(moveSpeed * delta)
210
+ );
211
+
212
+ // Collision Detection
213
+ let colliding = false;
214
+ for (const wall of wallBounds) {
215
+ if (
216
+ newPosition.x > wall.minX - collisionRadius &&
217
+ newPosition.x < wall.maxX + collisionRadius &&
218
+ newPosition.z > wall.minZ - collisionRadius &&
219
+ newPosition.z < wall.maxZ + collisionRadius
220
+ ) {
221
+ colliding = true;
222
+ break;
223
  }
224
  }
225
+
226
+ if (!colliding) {
227
+ soldier.position.copy(newPosition);
228
+ const angle = Math.atan2(moveDirection.x, moveDirection.z);
229
+ soldier.rotation.y = angle + Math.PI; // Orientation fix
230
+ }
231
+
232
+ // Animation Transition to Run
233
+ if (activeAction !== runAction) {
234
+ activeAction.fadeOut(0.2);
235
+ runAction.reset().fadeIn(0.2).play();
236
+ activeAction = runAction;
237
+ }
238
+ } else {
239
+ // Animation Transition to Idle
240
+ if (activeAction !== idleAction) {
241
+ activeAction.fadeOut(0.2);
242
+ idleAction.reset().fadeIn(0.2).play();
243
+ activeAction = idleAction;
244
+ }
245
  }
246
+ }
247
+
248
+ // Animation Loop
249
+ const clock = new THREE.Clock();
250
+ function animate() {
251
+ requestAnimationFrame(animate);
252
+ const delta = clock.getDelta();
253
+
254
+ if (mixer) mixer.update(delta);
255
+ updateSoldier(delta);
256
+
257
+ if (soldier) {
258
+ controls.target.copy(soldier.position);
259
+ const pos = soldier.position;
260
+ document.getElementById('position').textContent =
261
+ `(${pos.x.toFixed(2)}, ${pos.y.toFixed(2)}, ${pos.z.toFixed(2)})`;
262
+ document.getElementById('rotation').textContent =
263
+ soldier.rotation.y.toFixed(2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  }
265
+
266
+ controls.update();
267
+ renderer.render(scene, camera);
268
+ }
269
+ animate();
270
+
271
+ // Responsive Design
272
+ window.addEventListener('resize', () => {
273
+ camera.aspect = window.innerWidth / window.innerHeight;
274
+ camera.updateProjectionMatrix();
275
+ renderer.setSize(window.innerWidth, window.innerHeight);
276
+ });
277
+ </script>
278
+ </body>
279
+ </html>""")
280
 
281
  demo.launch()