Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -317,50 +317,70 @@ CODE_SYSTEM = (
|
|
| 317 |
" const canvas = document.getElementById('gameCanvas'); "
|
| 318 |
" const ctx = canvas.getContext('2d'); "
|
| 319 |
" const playerImg = new Image(); playerImg.src = 'sprite_player.png'; "
|
| 320 |
-
" const bgImg = new Image();
|
| 321 |
-
" const enemyImg = new Image();
|
| 322 |
" const keys = new Set(); "
|
| 323 |
" const bullets = []; "
|
| 324 |
" const enemies = []; "
|
| 325 |
" let score = 0; let health = 3; let frameCount = 0; let gameOver = false; "
|
| 326 |
-
"2. FOR TOP-DOWN SHOOTER declare player right after: "
|
| 327 |
" let player = {x: canvas.width/2-24, y: canvas.height/2-24, w:48, h:48, speed:4}; "
|
| 328 |
-
"
|
|
|
|
| 329 |
" function loadImg(img) { return new Promise(r => { img.onload = r; }); } "
|
| 330 |
" Promise.all([loadImg(playerImg), loadImg(bgImg), loadImg(enemyImg)]).then(startGame); "
|
| 331 |
-
"4. startGame()
|
| 332 |
" function startGame() { "
|
| 333 |
" window.addEventListener('keydown', e => keys.add(e.key)); "
|
| 334 |
" window.addEventListener('keyup', e => keys.delete(e.key)); "
|
| 335 |
" canvas.addEventListener('click', onShoot); "
|
| 336 |
" requestAnimationFrame(gameLoop); } "
|
| 337 |
-
"5. gameLoop()
|
| 338 |
" function gameLoop() { "
|
| 339 |
" if (gameOver) return; "
|
| 340 |
" ctx.drawImage(bgImg, 0, 0, canvas.width, canvas.height); "
|
| 341 |
-
" ...
|
| 342 |
" requestAnimationFrame(gameLoop); } "
|
| 343 |
-
"6. FOR TOP-DOWN SHOOTER movement -
|
| 344 |
" if (keys.has('w')||keys.has('W')||keys.has('ArrowUp')) player.y -= player.speed; "
|
| 345 |
" if (keys.has('s')||keys.has('S')||keys.has('ArrowDown')) player.y += player.speed; "
|
| 346 |
" if (keys.has('a')||keys.has('A')||keys.has('ArrowLeft')) player.x -= player.speed; "
|
| 347 |
" if (keys.has('d')||keys.has('D')||keys.has('ArrowRight')) player.x += player.speed; "
|
| 348 |
-
" player.x = Math.max(0, Math.min(canvas.width-player.w, player.x)); "
|
| 349 |
-
" player.y = Math.max(0, Math.min(canvas.height-player.h, player.y)); "
|
| 350 |
-
"7. FOR TOP-DOWN SHOOTER bullets -
|
| 351 |
" function onShoot(e) { "
|
| 352 |
-
" bullets.push({x:player.x+player.w/2-4, y:player.y-16, w:8, h:16, vy:-10}); } "
|
| 353 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
"8. FOR TOP-DOWN SHOOTER enemies - spawn every 120 frames, fall straight down: "
|
| 355 |
" frameCount++; "
|
| 356 |
-
" if (frameCount % 120 === 0)
|
| 357 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
" Remove if e.y > canvas.height. If overlaps player: health--; remove enemy. "
|
| 359 |
-
" Check bullet-enemy collision: remove both. score += 10. "
|
| 360 |
"9. Draw player: ctx.drawImage(playerImg, player.x, player.y, player.w, player.h). "
|
| 361 |
-
"10. GAME OVER when health<=0: set gameOver=true, draw
|
| 362 |
-
"
|
| 363 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 364 |
"12. FOR PLATFORMER: gravity velY+=0.5, jump ArrowUp/W/Space velY=-12 when grounded. "
|
| 365 |
" Set grounded=false BEFORE platform loop. Set true and velY=0 only on landing. "
|
| 366 |
" Full-width ground at y=420. "
|
|
@@ -451,9 +471,11 @@ def _wrap_in_html(snippet: str, theme: str) -> str:
|
|
| 451 |
def _build_preview(html_code: str) -> str:
|
| 452 |
encoded = base64.b64encode(html_code.encode("utf-8")).decode("ascii")
|
| 453 |
return (
|
|
|
|
| 454 |
f'<iframe src="data:text/html;base64,{encoded}" '
|
| 455 |
-
f'style="width:{CANVAS_W}px;height:{CANVAS_H}px;border:none;
|
| 456 |
-
'
|
|
|
|
| 457 |
)
|
| 458 |
|
| 459 |
|
|
|
|
| 317 |
" const canvas = document.getElementById('gameCanvas'); "
|
| 318 |
" const ctx = canvas.getContext('2d'); "
|
| 319 |
" const playerImg = new Image(); playerImg.src = 'sprite_player.png'; "
|
| 320 |
+
" const bgImg = new Image(); bgImg.src = 'sprite_background.png'; "
|
| 321 |
+
" const enemyImg = new Image(); enemyImg.src = 'sprite_enemy.png'; "
|
| 322 |
" const keys = new Set(); "
|
| 323 |
" const bullets = []; "
|
| 324 |
" const enemies = []; "
|
| 325 |
" let score = 0; let health = 3; let frameCount = 0; let gameOver = false; "
|
| 326 |
+
"2. FOR TOP-DOWN SHOOTER declare player right after (center of canvas, NOT at bottom): "
|
| 327 |
" let player = {x: canvas.width/2-24, y: canvas.height/2-24, w:48, h:48, speed:4}; "
|
| 328 |
+
" DO NOT set player.y = canvas.height - 24. Player starts in the CENTER. "
|
| 329 |
+
"3. Use Promise.all AFTER all declarations: "
|
| 330 |
" function loadImg(img) { return new Promise(r => { img.onload = r; }); } "
|
| 331 |
" Promise.all([loadImg(playerImg), loadImg(bgImg), loadImg(enemyImg)]).then(startGame); "
|
| 332 |
+
"4. startGame() ONLY sets up listeners and starts the loop: "
|
| 333 |
" function startGame() { "
|
| 334 |
" window.addEventListener('keydown', e => keys.add(e.key)); "
|
| 335 |
" window.addEventListener('keyup', e => keys.delete(e.key)); "
|
| 336 |
" canvas.addEventListener('click', onShoot); "
|
| 337 |
" requestAnimationFrame(gameLoop); } "
|
| 338 |
+
"5. gameLoop() NEVER redeclares canvas or ctx: "
|
| 339 |
" function gameLoop() { "
|
| 340 |
" if (gameOver) return; "
|
| 341 |
" ctx.drawImage(bgImg, 0, 0, canvas.width, canvas.height); "
|
| 342 |
+
" ... update and draw everything ... "
|
| 343 |
" requestAnimationFrame(gameLoop); } "
|
| 344 |
+
"6. FOR TOP-DOWN SHOOTER movement - 4 directions, clamp inside canvas: "
|
| 345 |
" if (keys.has('w')||keys.has('W')||keys.has('ArrowUp')) player.y -= player.speed; "
|
| 346 |
" if (keys.has('s')||keys.has('S')||keys.has('ArrowDown')) player.y += player.speed; "
|
| 347 |
" if (keys.has('a')||keys.has('A')||keys.has('ArrowLeft')) player.x -= player.speed; "
|
| 348 |
" if (keys.has('d')||keys.has('D')||keys.has('ArrowRight')) player.x += player.speed; "
|
| 349 |
+
" player.x = Math.max(0, Math.min(canvas.width - player.w, player.x)); "
|
| 350 |
+
" player.y = Math.max(0, Math.min(canvas.height - player.h, player.y)); "
|
| 351 |
+
"7. FOR TOP-DOWN SHOOTER bullets - MOUSE CLICK fires bullet straight UP ONLY, NO vx: "
|
| 352 |
" function onShoot(e) { "
|
| 353 |
+
" bullets.push({x: player.x+player.w/2-4, y: player.y-16, w:8, h:16, vy:-10}); } "
|
| 354 |
+
" Inside gameLoop update bullets like this EXACTLY: "
|
| 355 |
+
" for (let i = bullets.length-1; i >= 0; i--) { "
|
| 356 |
+
" bullets[i].y += bullets[i].vy; "
|
| 357 |
+
" ctx.fillStyle='yellow'; ctx.fillRect(bullets[i].x, bullets[i].y, 8, 16); "
|
| 358 |
+
" if (bullets[i].y + 16 < 0) { bullets.splice(i,1); continue; } "
|
| 359 |
+
" for (let j = enemies.length-1; j >= 0; j--) { "
|
| 360 |
+
" if (bullets[i] && bullets[i].x < enemies[j].x+32 && bullets[i].x+8 > enemies[j].x "
|
| 361 |
+
" && bullets[i].y < enemies[j].y+32 && bullets[i].y+16 > enemies[j].y) { "
|
| 362 |
+
" enemies.splice(j,1); bullets.splice(i,1); score+=10; break; } } } "
|
| 363 |
"8. FOR TOP-DOWN SHOOTER enemies - spawn every 120 frames, fall straight down: "
|
| 364 |
" frameCount++; "
|
| 365 |
+
" if (frameCount % 120 === 0) { "
|
| 366 |
+
" enemies.push({x: Math.random()*(canvas.width-32), y:0, w:32, h:32, "
|
| 367 |
+
" speed: Math.min(1 + score/500, 3.5)}); } "
|
| 368 |
+
" speed formula Math.min(1 + score/500, 3.5) means enemies start slow and "
|
| 369 |
+
" get faster as score increases but NEVER exceed speed 3.5. "
|
| 370 |
+
" Each frame: e.y += e.speed; ctx.drawImage(enemyImg,e.x,e.y,32,32); "
|
| 371 |
" Remove if e.y > canvas.height. If overlaps player: health--; remove enemy. "
|
|
|
|
| 372 |
"9. Draw player: ctx.drawImage(playerImg, player.x, player.y, player.w, player.h). "
|
| 373 |
+
"10. GAME OVER when health<=0: set gameOver=true, draw dark overlay + "
|
| 374 |
+
" 'GAME OVER' text + score on canvas center, draw a green Restart button rect, "
|
| 375 |
+
" add ONE-TIME canvas click listener: canvas.addEventListener('click', restartHandler); "
|
| 376 |
+
" function restartHandler() { canvas.removeEventListener('click', restartHandler); reset(); } "
|
| 377 |
+
"11. reset() resets ALL variables to initial values then calls requestAnimationFrame(gameLoop): "
|
| 378 |
+
" function reset() { "
|
| 379 |
+
" player.x=canvas.width/2-24; player.y=canvas.height/2-24; "
|
| 380 |
+
" bullets.length=0; enemies.length=0; "
|
| 381 |
+
" score=0; health=3; frameCount=0; gameOver=false; "
|
| 382 |
+
" canvas.addEventListener('click', onShoot); "
|
| 383 |
+
" requestAnimationFrame(gameLoop); } "
|
| 384 |
"12. FOR PLATFORMER: gravity velY+=0.5, jump ArrowUp/W/Space velY=-12 when grounded. "
|
| 385 |
" Set grounded=false BEFORE platform loop. Set true and velY=0 only on landing. "
|
| 386 |
" Full-width ground at y=420. "
|
|
|
|
| 471 |
def _build_preview(html_code: str) -> str:
|
| 472 |
encoded = base64.b64encode(html_code.encode("utf-8")).decode("ascii")
|
| 473 |
return (
|
| 474 |
+
f'<div style="width:{CANVAS_W}px;height:{CANVAS_H}px;overflow:hidden;border-radius:12px;">'
|
| 475 |
f'<iframe src="data:text/html;base64,{encoded}" '
|
| 476 |
+
f'style="width:{CANVAS_W}px;height:{CANVAS_H}px;border:none;background:#000;display:block;" '
|
| 477 |
+
f'scrolling="no" '
|
| 478 |
+
'sandbox="allow-scripts" title="Game Preview"></iframe></div>'
|
| 479 |
)
|
| 480 |
|
| 481 |
|