awacke1 commited on
Commit
9389d2d
·
verified ·
1 Parent(s): 61368a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -137
app.py CHANGED
@@ -20,7 +20,7 @@ nest_asyncio.apply()
20
  st.set_page_config(page_title="Galaxian Snake 3D Multiplayer", layout="wide")
21
 
22
  st.title("Galaxian Snake 3D Multiplayer")
23
- st.write("Navigate a 3D city with others, eat food, and chat in real-time!")
24
 
25
  # Sliders for container size
26
  max_width = min(1200, st.session_state.get('window_width', 1200))
@@ -127,7 +127,7 @@ async def start_websocket_server():
127
  server = await websockets.serve(websocket_handler, '0.0.0.0', 8765)
128
  st.session_state['server_running'] = True
129
  st.session_state['server'] = server
130
- await asyncio.Future() # Run forever until cancelled
131
 
132
  # Chat Functions
133
  async def save_chat_entry(username, message):
@@ -157,8 +157,8 @@ html_code = f"""
157
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
158
  <title>Galaxian Snake 3D Multiplayer</title>
159
  <style>
160
- body {{ margin: 0; overflow: hidden; font-family: Arial, sans-serif; }}
161
- #gameContainer {{ width: {container_width}px; height: {container_height}px; position: relative; background: #000; }}
162
  canvas {{ width: 100%; height: 100%; display: block; }}
163
  .ui-container {{
164
  position: absolute; top: 10px; left: 10px; color: white;
@@ -184,11 +184,10 @@ html_code = f"""
184
  <div id="players">Players: 1</div>
185
  <div id="score">Score: 0</div>
186
  <div id="length">Length: 3</div>
187
- <div id="leaderboard"></div>
188
  </div>
189
  <div id="chatBox"></div>
190
  <div class="controls">
191
- <p>Controls: W/A/S/D or Arrow Keys to move</p>
192
  <p>Eat yellow cubes to grow and score!</p>
193
  </div>
194
  <div id="debug"></div>
@@ -198,18 +197,16 @@ html_code = f"""
198
  <script>
199
  try {{
200
  console.log('Starting game initialization...');
201
- // Game variables
202
- let score = 0, players = {{}}, foodItems = [], lSysCreatures = [], quineAgents = [], buildings = [], lights = [];
203
- let snake = [], moveDir = new THREE.Vector3(1, 0, 0), moveCounter = 0, moveInterval = 0.05; // Faster movement
204
- const initialLength = 3, playerName = "{st.session_state.username}";
205
- const highScores = JSON.parse(localStorage.getItem('highScores')) || [];
206
  let ws = new WebSocket('ws://localhost:8765');
207
  const debug = document.getElementById('debug');
208
 
209
  // Scene setup
210
  const scene = new THREE.Scene();
211
  const camera = new THREE.PerspectiveCamera(75, {container_width} / {container_height}, 0.1, 1000);
212
- camera.position.set(0, 15, 20); // Lower, closer camera
213
  console.log('Camera initialized at:', camera.position);
214
 
215
  const renderer = new THREE.WebGLRenderer({{ antialias: true }});
@@ -229,7 +226,7 @@ html_code = f"""
229
 
230
  // Ground
231
  const textureLoader = new THREE.TextureLoader();
232
- const groundGeometry = new THREE.PlaneGeometry(200, 200);
233
  const groundMaterial = new THREE.MeshStandardMaterial({{
234
  color: 0x1a5e1a,
235
  bumpMap: textureLoader.load('https://threejs.org/examples/textures/terrain/grasslight-big-nm.jpg'),
@@ -238,9 +235,20 @@ html_code = f"""
238
  const ground = new THREE.Mesh(groundGeometry, groundMaterial);
239
  ground.rotation.x = -Math.PI / 2;
240
  ground.receiveShadow = true;
 
241
  scene.add(ground);
242
  console.log('Ground added');
243
 
 
 
 
 
 
 
 
 
 
 
244
  // Building rules
245
  const buildingColors = [0x888888, 0x666666, 0x999999];
246
  const buildingRules = [
@@ -294,36 +302,18 @@ html_code = f"""
294
  return buildingGroup;
295
  }}
296
 
297
- function createCity() {{
298
- const citySize = 3, spacing = 20; // Wider spacing
299
- for (let x = -citySize; x <= citySize; x++) {{
300
- for (let z = -citySize; z <= citySize; z++) {{
301
- if (Math.random() < 0.7) continue; // Fewer buildings
302
- const position = new THREE.Vector3(x * spacing, 0, z * spacing);
303
- const building = interpretLSystem(buildingRules[0], position, new THREE.Euler());
304
- scene.add(building);
305
- buildings.push(building);
306
- console.log('Building at:', position);
307
- }}
308
- }}
309
- const roadWidth = 12; // Wider roads
310
- for (let x = -citySize; x <= citySize; x++) {{
311
- const road = new THREE.Mesh(
312
- new THREE.PlaneGeometry(roadWidth, citySize * 2 * spacing + roadWidth),
313
- new THREE.MeshStandardMaterial({{color: 0x333333}})
314
  );
315
- road.rotation.x = -Math.PI / 2;
316
- road.position.set(x * spacing, 0.01, 0);
317
- scene.add(road);
318
- }}
319
- for (let z = -citySize; z <= citySize; z++) {{
320
- const road = new THREE.Mesh(
321
- new THREE.PlaneGeometry(citySize * 2 * spacing + roadWidth, roadWidth),
322
- new THREE.MeshStandardMaterial({{color: 0x333333}})
323
- );
324
- road.rotation.x = -Math.PI / 2;
325
- road.position.set(0, 0.01, z * spacing);
326
- scene.add(road);
327
  }}
328
  }}
329
 
@@ -333,120 +323,79 @@ html_code = f"""
333
  new THREE.BoxGeometry(1, 1, 1),
334
  new THREE.MeshStandardMaterial({{color: 0xffff00}})
335
  );
336
- const x = (Math.random() * 60) - 30;
337
- const z = (Math.random() * 60) - 30;
338
- food.position.set(x, 0.5, z);
 
 
339
  foodItems.push(food);
340
  scene.add(food);
341
  console.log('Food at:', food.position);
342
  }}
343
  }}
344
 
345
- function resetSnake() {{
346
- snake.forEach(seg => scene.remove(seg));
347
- snake = [];
348
- const snakeMaterial = new THREE.MeshStandardMaterial({{color: 0x00ff00}});
349
- for (let i = 0; i < initialLength; i++) {{
350
- const segment = new THREE.Mesh(new THREE.SphereGeometry(0.5, 16, 16), snakeMaterial);
351
- segment.position.set(-i * 1.2, 0.5, 0);
352
- segment.castShadow = true;
353
- snake.push(segment);
354
- scene.add(segment);
355
- }}
356
- moveDir.set(1, 0, 0);
357
- players[playerName] = {{ snake: snake, score: 0, length: initialLength }};
358
- console.log('Snake reset at:', snake[0].position);
359
- }}
360
-
361
  // Controls
362
- const keys = {{w: false, a: false, s: false, d: false}};
363
  document.addEventListener('keydown', (event) => {{
364
- switch (event.key.toLowerCase()) {{
365
- case 'w': case 'arrowup': keys.w = true; break;
366
- case 'a': case 'arrowleft': keys.a = true; break;
367
- case 's': case 'arrowdown': keys.s = true; break;
368
- case 'd': case 'arrowright': keys.d = true; break;
369
  }}
370
  }});
371
  document.addEventListener('keyup', (event) => {{
372
- switch (event.key.toLowerCase()) {{
373
- case 'w': case 'arrowup': keys.w = false; break;
374
- case 'a': case 'arrowleft': keys.a = false; break;
375
- case 's': case 'arrowdown': keys.s = false; break;
376
- case 'd': case 'arrowright': keys.d = false; break;
377
  }}
378
  }});
379
 
380
- function updateSnake(delta) {{
381
- moveCounter += delta;
382
- if (moveCounter < moveInterval) return;
383
- moveCounter = 0;
384
-
385
- if (keys.w && moveDir.z !== 1) moveDir.set(0, 0, -1);
386
- else if (keys.s && moveDir.z !== -1) moveDir.set(0, 0, 1);
387
- else if (keys.a && moveDir.x !== 1) moveDir.set(-1, 0, 0);
388
- else if (keys.d && moveDir.x !== -1) moveDir.set(1, 0, 0);
389
-
390
- const head = snake[0];
391
- const newHead = new THREE.Mesh(head.geometry, head.material);
392
- newHead.position.copy(head.position).add(moveDir.clone().multiplyScalar(2)); // Faster step
393
- newHead.castShadow = true;
394
-
395
- if (Math.abs(newHead.position.x) > 100 || Math.abs(newHead.position.z) > 100) {{
396
- resetSnake();
397
- return;
398
- }}
399
-
400
- for (let i = 1; i < snake.length; i++) {{
401
- if (newHead.position.distanceTo(snake[i].position) < 0.9) {{
402
- resetSnake();
403
- return;
404
  }}
405
- }}
406
-
407
- for (const building of buildings) {{
408
- building.traverse((child) => {{
409
- if (child.isMesh) {{
410
- const buildingBox = new THREE.Box3().setFromObject(child);
411
- const headPos = newHead.position.clone();
412
- if (headPos.x + 0.5 > buildingBox.min.x && headPos.x - 0.5 < buildingBox.max.x &&
413
- headPos.z + 0.5 > buildingBox.min.z && headPos.z - 0.5 < buildingBox.max.z) {{
414
- resetSnake();
415
- return;
416
- }}
417
- }}
418
- }});
419
- }}
420
-
421
- snake.unshift(newHead);
422
- scene.add(newHead);
423
-
424
- for (let i = foodItems.length - 1; i >= 0; i--) {{
425
- if (newHead.position.distanceTo(foodItems[i].position) < 1) {{
426
- scene.remove(foodItems[i]);
427
  foodItems.splice(i, 1);
428
  spawnFood();
429
- score += 2;
430
- players[playerName].score = score;
431
- players[playerName].length = snake.length;
432
- updateUI();
433
- break;
434
- }} else {{
435
- const tail = snake.pop();
436
- scene.remove(tail);
437
  }}
438
- }}
 
 
 
 
 
 
 
439
 
440
- const headPos = newHead.position;
441
- camera.position.set(headPos.x, 15, headPos.z + 20); // Closer chase cam
442
- camera.lookAt(headPos);
443
  }}
444
 
445
  function updateUI() {{
446
  document.getElementById('players').textContent = `Players: ${{Object.keys(players).length}}`;
447
  document.getElementById('score').textContent = `Score: ${{score}}`;
448
- document.getElementById('length').textContent = `Length: ${{snake.length}}`;
449
- debug.innerHTML = `Scene: ${{scene.children.length}}<br>Buildings: ${{buildings.length}}<br>Snake: ${{snake.length}}`;
450
  }}
451
 
452
  // WebSocket chat
@@ -469,7 +418,7 @@ html_code = f"""
469
  const delta = (currentTime - lastTime) / 1000;
470
  lastTime = currentTime;
471
 
472
- updateSnake(delta);
473
  spawnFood();
474
  updateUI();
475
 
@@ -477,8 +426,7 @@ html_code = f"""
477
  }}
478
 
479
  // Initialize
480
- resetSnake();
481
- createCity();
482
  spawnFood();
483
  animate();
484
  console.log('Game initialized');
@@ -523,8 +471,8 @@ if not st.session_state.get('server_running', False):
523
 
524
  st.sidebar.write("""
525
  ### How to Play
526
- - **W/A/S/D or Arrow Keys**: Move your snake
527
  - Eat yellow cubes to grow and score
528
- - Wider roads and fewer buildings for easier movement
529
  - Chat with other players in real-time
530
  """)
 
20
  st.set_page_config(page_title="Galaxian Snake 3D Multiplayer", layout="wide")
21
 
22
  st.title("Galaxian Snake 3D Multiplayer")
23
+ st.write("Navigate a 3D city with continuous motion, eat food, and chat in real-time!")
24
 
25
  # Sliders for container size
26
  max_width = min(1200, st.session_state.get('window_width', 1200))
 
127
  server = await websockets.serve(websocket_handler, '0.0.0.0', 8765)
128
  st.session_state['server_running'] = True
129
  st.session_state['server'] = server
130
+ await asyncio.Future()
131
 
132
  # Chat Functions
133
  async def save_chat_entry(username, message):
 
157
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
158
  <title>Galaxian Snake 3D Multiplayer</title>
159
  <style>
160
+ body {{ margin: 0; overflow: hidden; font-family: Arial, sans-serif; background: #000; }}
161
+ #gameContainer {{ width: {container_width}px; height: {container_height}px; position: relative; }}
162
  canvas {{ width: 100%; height: 100%; display: block; }}
163
  .ui-container {{
164
  position: absolute; top: 10px; left: 10px; color: white;
 
184
  <div id="players">Players: 1</div>
185
  <div id="score">Score: 0</div>
186
  <div id="length">Length: 3</div>
 
187
  </div>
188
  <div id="chatBox"></div>
189
  <div class="controls">
190
+ <p>Controls: W/A/S/D or Arrow Keys to steer</p>
191
  <p>Eat yellow cubes to grow and score!</p>
192
  </div>
193
  <div id="debug"></div>
 
197
  <script>
198
  try {{
199
  console.log('Starting game initialization...');
200
+ let score = 0, players = {{}}, foodItems = [], buildings = [];
201
+ let snake, moveLeft = false, moveRight = false, moveUp = false, moveDown = false;
202
+ const playerName = "{st.session_state.username}";
 
 
203
  let ws = new WebSocket('ws://localhost:8765');
204
  const debug = document.getElementById('debug');
205
 
206
  // Scene setup
207
  const scene = new THREE.Scene();
208
  const camera = new THREE.PerspectiveCamera(75, {container_width} / {container_height}, 0.1, 1000);
209
+ camera.position.set(0, 15, 20);
210
  console.log('Camera initialized at:', camera.position);
211
 
212
  const renderer = new THREE.WebGLRenderer({{ antialias: true }});
 
226
 
227
  // Ground
228
  const textureLoader = new THREE.TextureLoader();
229
+ const groundGeometry = new THREE.PlaneGeometry(200, 1000); // Long scrolling ground
230
  const groundMaterial = new THREE.MeshStandardMaterial({{
231
  color: 0x1a5e1a,
232
  bumpMap: textureLoader.load('https://threejs.org/examples/textures/terrain/grasslight-big-nm.jpg'),
 
235
  const ground = new THREE.Mesh(groundGeometry, groundMaterial);
236
  ground.rotation.x = -Math.PI / 2;
237
  ground.receiveShadow = true;
238
+ ground.position.z = -500; // Start far back
239
  scene.add(ground);
240
  console.log('Ground added');
241
 
242
+ // Player (Snake Head)
243
+ const snakeGeometry = new THREE.BoxGeometry(1, 1, 1);
244
+ const snakeMaterial = new THREE.MeshPhongMaterial({{ color: 0x00ff00 }});
245
+ snake = new THREE.Mesh(snakeGeometry, snakeMaterial);
246
+ snake.position.set(0, 0.5, 0);
247
+ snake.castShadow = true;
248
+ scene.add(snake);
249
+ players[playerName] = {{ snake: snake, score: 0, length: 1 }};
250
+ console.log('Snake initialized at:', snake.position);
251
+
252
  // Building rules
253
  const buildingColors = [0x888888, 0x666666, 0x999999];
254
  const buildingRules = [
 
302
  return buildingGroup;
303
  }}
304
 
305
+ function spawnBuildings() {{
306
+ const cityWidth = 40, cityDepth = -1000;
307
+ for (let i = buildings.length; i < 20; i++) {{
308
+ const position = new THREE.Vector3(
309
+ Math.random() * cityWidth - cityWidth / 2,
310
+ 0,
311
+ cityDepth + Math.random() * 1000
 
 
 
 
 
 
 
 
 
 
312
  );
313
+ const building = interpretLSystem(buildingRules[0], position, new THREE.Euler());
314
+ buildings.push(building);
315
+ scene.add(building);
316
+ console.log('Building at:', position);
 
 
 
 
 
 
 
 
317
  }}
318
  }}
319
 
 
323
  new THREE.BoxGeometry(1, 1, 1),
324
  new THREE.MeshStandardMaterial({{color: 0xffff00}})
325
  );
326
+ food.position.set(
327
+ Math.random() * 40 - 20,
328
+ Math.random() * 10,
329
+ -1000
330
+ );
331
  foodItems.push(food);
332
  scene.add(food);
333
  console.log('Food at:', food.position);
334
  }}
335
  }}
336
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  // Controls
 
338
  document.addEventListener('keydown', (event) => {{
339
+ switch (event.code) {{
340
+ case 'ArrowLeft': case 'KeyA': moveLeft = true; break;
341
+ case 'ArrowRight': case 'KeyD': moveRight = true; break;
342
+ case 'ArrowUp': case 'KeyW': moveUp = true; break;
343
+ case 'ArrowDown': case 'KeyS': moveDown = true; break;
344
  }}
345
  }});
346
  document.addEventListener('keyup', (event) => {{
347
+ switch (event.code) {{
348
+ case 'ArrowLeft': case 'KeyA': moveLeft = false; break;
349
+ case 'ArrowRight': case 'KeyD': moveRight = false; break;
350
+ case 'ArrowUp': case 'KeyW': moveUp = false; break;
351
+ case 'ArrowDown': case 'KeyS': moveDown = false; break;
352
  }}
353
  }});
354
 
355
+ function updatePlayer(delta) {{
356
+ const speed = 10;
357
+ if (moveLeft && snake.position.x > -20) snake.position.x -= speed * delta;
358
+ if (moveRight && snake.position.x < 20) snake.position.x += speed * delta;
359
+ if (moveUp && snake.position.y < 15) snake.position.y += speed * delta;
360
+ if (moveDown && snake.position.y > 0.5) snake.position.y -= speed * delta;
361
+
362
+ // Continuous forward motion
363
+ const forwardSpeed = 20;
364
+ buildings.forEach(building => {{
365
+ building.position.z += forwardSpeed * delta;
366
+ if (building.position.z > 20) {{
367
+ building.position.z = -1000;
368
+ building.position.x = Math.random() * 40 - 20;
 
 
 
 
 
 
 
 
 
 
369
  }}
370
+ if (snake.position.distanceTo(building.position) < 5) {{
371
+ snake.position.set(0, 0.5, 0); // Reset on collision
372
+ }}
373
+ }});
374
+ foodItems.forEach((food, i) => {{
375
+ food.position.z += forwardSpeed * delta;
376
+ if (food.position.z > 20) {{
377
+ scene.remove(food);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  foodItems.splice(i, 1);
379
  spawnFood();
 
 
 
 
 
 
 
 
380
  }}
381
+ if (snake.position.distanceTo(food.position) < 1) {{
382
+ scene.remove(food);
383
+ foodItems.splice(i, 1);
384
+ score += 10;
385
+ players[playerName].length += 1;
386
+ spawnFood();
387
+ }}
388
+ }});
389
 
390
+ camera.position.set(snake.position.x, snake.position.y + 15, snake.position.z + 20);
391
+ camera.lookAt(snake.position);
 
392
  }}
393
 
394
  function updateUI() {{
395
  document.getElementById('players').textContent = `Players: ${{Object.keys(players).length}}`;
396
  document.getElementById('score').textContent = `Score: ${{score}}`;
397
+ document.getElementById('length').textContent = `Length: ${{players[playerName].length}}`;
398
+ debug.innerHTML = `Scene: ${{scene.children.length}}<br>Buildings: ${{buildings.length}}<br>Food: ${{foodItems.length}}`;
399
  }}
400
 
401
  // WebSocket chat
 
418
  const delta = (currentTime - lastTime) / 1000;
419
  lastTime = currentTime;
420
 
421
+ updatePlayer(delta);
422
  spawnFood();
423
  updateUI();
424
 
 
426
  }}
427
 
428
  // Initialize
429
+ spawnBuildings();
 
430
  spawnFood();
431
  animate();
432
  console.log('Game initialized');
 
471
 
472
  st.sidebar.write("""
473
  ### How to Play
474
+ - **W/A/S/D or Arrow Keys**: Steer the snake (up/down/left/right)
475
  - Eat yellow cubes to grow and score
476
+ - World moves continuously toward you
477
  - Chat with other players in real-time
478
  """)