< < < < <Procedural Platformer < body { margin: 0; padding: 0; overflow: hidden; background-color: #000; display: flex; justify-content: center; align-items: center; height: 100vh; font-family: 'Courier New', Courier, monospace; } canvas { box-shadow: 0 0 20px rgba(0,0,0,0.5); } #ui { position: absolute; top: 20px; left: 20px; color: white; font-size: 24px; text-shadow: 2px 2px #000; pointer-events: none; z-index: 10; } <Coins: 0 < < const config = { type: Phaser.AUTO, width: 800, height: 600, physics: { default: 'arcade', arcade: { gravity: { y: 1000 }, debug: false } }, scene: { preload: preload, create: create, update: update } }; const game = new Phaser.Game(config); let player; let cursors; let platforms; let coins; let enemies; let goal; let score = 0; let scoreText; let isGameOver = false; function preload() { // Procedural Texture Generation // 1. Player Texture const playerCanvas = this.textures.createCanvas('player', 32, 32); const playerCtx = playerCanvas.getContext(); playerCtx.fillStyle = '#ff0000'; playerCtx.fillRect(0, 0, 32, 32); playerCtx.fillStyle = '#ffffff'; playerCtx.fillRect(8, 8, 8, 8); playerCtx.fillRect(16, 8, 8, 8); playerCtx.refresh(); // 2. Enemy Texture const enemyCanvas = this.textures.createCanvas('enemy', 32, 32); const enemyCtx = enemyCanvas.getContext(); enemyCtx.fillStyle = '#800080'; enemyCtx.fillRect(0, 0, 32, 32); enemyCtx.fillStyle = '#ffff00'; enemyCtx.fillRect(4, 4, 8, 8); enemyCtx.fillRect(20, 4, 8, 8); enemyCtx.refresh(); // 3. Coin Texture const coinCanvas = this.textures.createCanvas('coin', 20, 20); const coinCtx = coinCanvas.getContext(); coinCtx.fillStyle = '#ffd700'; coinCtx.beginPath(); coinCtx.arc(10, 10, 10, 0, Math.PI * 2); coinCtx.fill(); coinCtx.strokeStyle = '#b8860b'; coinCtx.lineWidth = 2; coinCtx.stroke(); coinCtx.refresh(); // 4. Platform Texture const platCanvas = this.textures.createCanvas('platform', 32, 32); const platCtx = platCanvas.getContext(); platCtx.fillStyle = '#8b4513'; platCtx.fillRect(0, 0, 32, 32); platCtx.fillStyle = '#228b22'; platCtx.fillRect(0, 0, 32, 8); platCtx.strokeStyle = '#5d2e0c'; platCtx.strokeRect(0, 0, 32, 32); platCtx.refresh(); // 5. Goal Texture const goalCanvas = this.textures.createCanvas('goal', 32, 64); const goalCtx = goalCanvas.getContext(); goalCtx.fillStyle = '#808080'; goalCtx.fillRect(12, 0, 8, 64); goalCtx.fillStyle = '#ff0000'; goalCtx.fillRect(20, 0, 12, 20); goalCtx.refresh(); } function create() { const worldWidth = 3200; const worldHeight = 600; this.physics.world.setBounds(0, 0, worldWidth, worldHeight); // Background color this.cameras.main.setBackgroundColor('#87ceeb'); // Groups platforms = this.physics.add.staticGroup(); coins = this.physics.add.group(); enemies = this.physics.add.group(); // Floor for (let x = 0; x << world worldWidth; x += 32) { platforms.create(x + 16, 584, 'platform'); } // Procedural Level Design const layout = [ { x: 400, y: 450, w: 200, h: 32 }, { x: 700, y: 350, w: 200, h: 32 }, { x: 1000, y: 450, w: 300, h: 32 }, { x: 1400, y: 300, w: 200, h: 32 }, { x: 1700, y: 400, w: 200, h: 32 }, { x: 2000, y: 300, w: 300, h: 32 }, { x: 2400, y: 450, w: 200, h: 32 }, { x: 2700, y: 350, w: 200, h: 32 }, ]; layout.forEach(p => { for (let x = p.x; x << p p.x + p.w; x += 32) { platforms.create(x + 16, p.y, 'platform'); } }); // Coins const coinPositions = [ {x: 450, y: 420}, {x: 500, y: 420}, {x: 750, y: 320}, {x: 1100, y: 420}, {x: 1200, y: 420}, {x: 1450, y: 270}, {x: 1750, y: 370}, {x: 2100, y: 270}, {x: 2200, y: 270}, {x: 2450, y: 420}, {x: 2750, y: 320} ]; coinPositions.forEach(pos => { coins.create(pos.x, pos.y, 'coin'); }); // Enemies const enemyPositions = [ {x: 600, y: 552, range: 100}, {x: 1100, y: 420, range: 100}, {x: 1800, y: 552, range: 150}, {x: 2200, y: 268, range: 100}, {x: 2600, y: 552, range: 100}, ]; enemyPositions.forEach(pos => { const enemy = enemies.create(pos.x, pos.y, 'enemy'); enemy.setCollideWorldBounds(true); enemy.setBounce(1); enemy.setVelocityX(100); enemy.setData('range', pos.range); enemy.setData('startX', pos.x); }); // Goal goal = this.physics.add.staticSprite(3100, 520, 'goal'); // Player player = this.physics.add.sprite(100, 500, 'player'); player.setCollideWorldBounds(true); player.setDragX(1000); // Camera this.cameras.main.setBounds(0, 0, worldWidth, worldHeight); this.cameras.main.startFollow(player); // UI scoreText = document.getElementById('ui'); // Collisions this.physics.add.collider(player, platforms); this.physics.add.collider(enemies, platforms); this.physics.add.overlap(player, coins, collectCoin, null, this); this.physics.add.collider(player, enemies, handleEnemyCollision, null, this); this.physics.add.overlap(player, goal, reachGoal, null, this); cursors = this.input.keyboard.createCursorKeys(); } function update() { if (isGameOver) return; if (cursors.left.isDown) { player.setVelocityX(-200); } else if (cursors.right.isDown) { player.setVelocityX(200); } if ((cursors.up.isDown || cursors.space.isDown) && player.body.touching.down) { player.setVelocityY(-500); } // Enemy AI enemies.getChildren().forEach(enemy => { const startX = enemy.getData('startX'); const range = enemy.getData('range'); if (enemy.x > startX + range || enemy.x << start startX - range) { enemy.setVelocityX(enemy.body.velocity.x * -1); } }); } function collectCoin(player, coin) { coin.disableBody(true, true); score += 10; scoreText.innerText = `Coins: ${score}`; } function handleEnemyCollision(player, enemy) { if (player.body.velocity.y > 0 && player.y << enemy enemy.y - 10) { // Stomp enemy enemy.disableBody(true, true); player.setVelocityY(-300); } else { // Player hit enemy gameOver(this, "Game Over! You hit an enemy."); } } function reachGoal(player, goal) { gameOver(this, `You Win! Final Score: ${score}`); } function gameOver(scene, message) { isGameOver = true; scene.physics.pause(); player.setTint(0xff0000); const overlay = scene.add.graphics(); overlay.fillStyle(0x000000, 0.7); overlay.fillRect(0, 0, 800, 600); overlay.setScrollFactor(0); const text = scene.add.text(400, 300, message, { fontSize: '32px', fill: '#fff', align: 'center' }).setOrigin(0.5).setScrollFactor(0); scene.add.text(400, 350, 'Press F5 to Restart', { fontSize: '20px', fill: '#fff' }).setOrigin(0.5).setScrollFactor(0); }