/** * TestVisualAudioScene.js * Demo scene: Kai speaks, dreadlocks wave, leaves fall */ class TestVisualAudioScene extends Phaser.Scene { constructor() { super({ key: 'TestVisualAudioScene' }); } preload() { console.log('🎬 Loading Test Visual & Audio Scene...'); // Load Kai voice this.load.audio('kai_test_voice', 'assets/audio/voices/kai/kai_test_01.mp3'); // Load music (if exists) if (this.cache.audio.exists('music/forest_ambient')) { console.log('✅ Music ready'); } // Load Kai sprite (placeholder for now) // this.load.image('kai_idle', 'assets/references/main_characters/kai/animations/idle/kai_idle_frame1.png'); } create() { console.log('🎨 Creating Test Scene...'); const width = this.cameras.main.width; const height = this.cameras.main.height; // Background this.cameras.main.setBackgroundColor('#7cfc00'); // Grassland green // Title const title = this.add.text(width / 2, 50, '🎨 VISUAL & AUDIO TEST', { fontSize: '32px', fontFamily: 'Arial', color: '#ffffff', stroke: '#000000', strokeThickness: 4 }); title.setOrigin(0.5); title.setDepth(1000); // Instructions const instructions = this.add.text(width / 2, 100, 'Use WASD to move Kai\nStep on YELLOW TILE to trigger voice\nWatch dreadlocks wave in wind\nWatch leaves fall', { fontSize: '16px', fontFamily: 'Arial', color: '#ffffff', stroke: '#000000', strokeThickness: 3, align: 'center' }); instructions.setOrigin(0.5); instructions.setDepth(1000); // Create ground tiles this.createGround(); // Create Kai (simple placeholder) this.createKai(); // Initialize systems this.initSystems(); // Create falling leaves this.createFallingLeaves(); // Create wind effect on Kai's dreadlocks this.createWindEffect(); // Camera follow this.cameras.main.startFollow(this.kai, true, 0.1, 0.1); this.cameras.main.setZoom(1.2); // Controls this.cursors = this.input.keyboard.createCursorKeys(); this.wasd = { up: this.input.keyboard.addKey('W'), down: this.input.keyboard.addKey('S'), left: this.input.keyboard.addKey('A'), right: this.input.keyboard.addKey('D') }; console.log('✅ Test Scene Ready!'); } createGround() { // Simple grass tiles const tileSize = 48; const gridWidth = 20; const gridHeight = 15; for (let y = 0; y < gridHeight; y++) { for (let x = 0; x < gridWidth; x++) { const worldX = x * tileSize; const worldY = y * tileSize; // Grass tile (light/dark alternating) const isLight = (x + y) % 2 === 0; const color = isLight ? 0x7cfc00 : 0x6ab04c; const tile = this.add.rectangle(worldX, worldY, tileSize, tileSize, color); tile.setOrigin(0); tile.setAlpha(0.5); } } // Audio trigger tile (YELLOW) const triggerX = 10; const triggerY = 7; const triggerTile = this.add.rectangle(triggerX * tileSize, triggerY * tileSize, tileSize, tileSize, 0xffff00); triggerTile.setOrigin(0); triggerTile.setAlpha(0.7); // Label const label = this.add.text(triggerX * tileSize + 24, triggerY * tileSize + 24, '🎙️', { fontSize: '28px' }); label.setOrigin(0.5); } createKai() { // Simplified Kai representation const kaiX = 240; const kaiY = 240; // Body this.kai = this.add.circle(kaiX, kaiY, 20, 0xffc0cb); // Pink body this.kai.setDepth(10); // Add physics this.physics.world.enable(this.kai); this.kai.body.setCollideWorldBounds(true); this.kai.speed = 150; // Dreadlocks (will animate) this.dreadlocks = []; const dreadCount = 8; const radius = 25; for (let i = 0; i < dreadCount; i++) { const angle = (i / dreadCount) * Math.PI * 2; const x = kaiX + Math.cos(angle) * radius; const y = kaiY + Math.sin(angle) * radius; const dread = this.add.rectangle(x, y, 4, 30, 0xff1493); // Hot pink dread.setOrigin(0.5, 0); // Pivot at top dread.angle = (angle * 180 / Math.PI) + 90; dread.setDepth(9); dread.baseAngle = dread.angle; dread.swayOffset = i * 0.5; // Stagger animation this.dreadlocks.push(dread); } // Name label this.kaiLabel = this.add.text(kaiX, kaiY - 40, 'KAI', { fontSize: '14px', fontFamily: 'Arial', color: '#ffffff', stroke: '#000000', strokeThickness: 3 }); this.kaiLabel.setOrigin(0.5); this.kaiLabel.setDepth(11); } initSystems() { // Audio Trigger System this.audioTriggers = new AudioTriggerSystem(this); // Add trigger at yellow tile (10, 7) this.audioTriggers.addTrigger(10, 7, 'kai_test_voice', { radius: 0, // Exact tile only volume: 1.0, oneTime: true, visualDebug: true, callback: () => { console.log('✅ Kai spoke her line!'); this.showSpeechBubble(); } }); // Biome Music System (if music exists) // this.biomeMusicSystem = new BiomeMusicSystem(this); // this.biomeMusicSystem.playBiomeMusic('grassland'); } showSpeechBubble() { // Show speech bubble above Kai const bubble = this.add.text(this.kai.x, this.kai.y - 60, '"My name is Kai..."', { fontSize: '12px', fontFamily: 'Arial', color: '#000000', backgroundColor: '#ffffff', padding: { x: 8, y: 4 } }); bubble.setOrigin(0.5); bubble.setDepth(100); // Fade out after 3 seconds this.tweens.add({ targets: bubble, alpha: 0, duration: 1000, delay: 2000, onComplete: () => bubble.destroy() }); } createFallingLeaves() { // Particle emitter for falling leaves this.leaves = []; // Create 20 leaves for (let i = 0; i < 20; i++) { this.time.delayedCall(i * 300, () => { this.spawnLeaf(); }); } } spawnLeaf() { const x = Phaser.Math.Between(0, this.cameras.main.width); const y = -20; const leaf = this.add.ellipse(x, y, 8, 12, 0x90ee90); leaf.setDepth(5); leaf.setAlpha(0.7); // Fall animation this.tweens.add({ targets: leaf, y: this.cameras.main.height + 50, duration: Phaser.Math.Between(4000, 7000), ease: 'Sine.InOut', onComplete: () => { leaf.destroy(); // Spawn new leaf this.spawnLeaf(); } }); // Sway side-to-side this.tweens.add({ targets: leaf, x: x + Phaser.Math.Between(-50, 50), duration: 2000, yoyo: true, repeat: -1, ease: 'Sine.InOut' }); // Rotate this.tweens.add({ targets: leaf, angle: 360, duration: 3000, repeat: -1, ease: 'Linear' }); } createWindEffect() { // Dreadlocks sway in wind this.time.addEvent({ delay: 50, loop: true, callback: () => { const time = this.time.now / 1000; this.dreadlocks.forEach((dread, i) => { const sway = Math.sin(time * 2 + dread.swayOffset) * 15; dread.angle = dread.baseAngle + sway; }); } }); } update() { if (!this.kai) return; // Movement this.kai.body.setVelocity(0); if (this.cursors.left.isDown || this.wasd.left.isDown) { this.kai.body.setVelocityX(-this.kai.speed); } else if (this.cursors.right.isDown || this.wasd.right.isDown) { this.kai.body.setVelocityX(this.kai.speed); } if (this.cursors.up.isDown || this.wasd.up.isDown) { this.kai.body.setVelocityY(-this.kai.speed); } else if (this.cursors.down.isDown || this.wasd.down.isDown) { this.kai.body.setVelocityY(this.kai.speed); } // Update dreadlocks position this.dreadlocks.forEach((dread, i) => { const angle = (i / this.dreadlocks.length) * Math.PI * 2; const radius = 25; dread.x = this.kai.x + Math.cos(angle) * radius; dread.y = this.kai.y + Math.sin(angle) * radius; }); // Update label position this.kaiLabel.setPosition(this.kai.x, this.kai.y - 40); // Update audio triggers this.audioTriggers.update(this.kai.x, this.kai.y); // ESC to return to menu if (this.input.keyboard.addKey('ESC').isDown) { this.scene.start('GameScene'); } } }