FAZA 17: 2.5D Minecraft-Style Terrain + Y-Layer Stacking + Custom Sprites
COMPLETED FEATURES: Custom Sprite Integration: - Player, Zombie, Merchant sprites (0.2 scale) - 11 custom sprites + 5 asset packs loaded - Auto-transparency processing (white/brown removal) - Gravestone system with atlas extraction 2.5D Minecraft-Style Terrain: - Volumetric blocks with 25px thickness - Strong left/right side shading (30%/50% darker) - Minecraft-style texture patterns (grass, dirt, stone) - Crisp black outlines for definition Y-Layer Stacking System: - GRASS_FULL: All green (elevation > 0.7) - GRASS_TOP: Green top + brown sides (elevation 0.4-0.7) - DIRT: All brown (elevation < 0.4) - Dynamic terrain depth based on height Floating Island World Edge: - Stone cliff walls at map borders - 2-tile transition zone - Elevation flattening for cliff drop-off effect - 100x100 world with defined boundaries Performance & Polish: - Canvas renderer for pixel-perfect sharpness - CSS image-rendering: crisp-edges - willReadFrequently optimization - No Canvas2D warnings Technical: - 3D volumetric trees and rocks - Hybrid rendering (2.5D terrain + 2D characters) - Procedural texture generation - Y-layer aware terrain type selection
This commit is contained in:
148
src/systems/SoundManager.js
Normal file
148
src/systems/SoundManager.js
Normal file
@@ -0,0 +1,148 @@
|
||||
class SoundManager {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.musicVolume = 0.3;
|
||||
this.sfxVolume = 0.5;
|
||||
this.isMuted = false;
|
||||
this.currentMusic = null;
|
||||
this.currentAmbient = null;
|
||||
console.log('🎵 SoundManager: Initialized');
|
||||
}
|
||||
|
||||
playSFX(key) {
|
||||
if (this.isMuted) return;
|
||||
|
||||
if (this.scene.sound.get(key)) {
|
||||
this.scene.sound.play(key, { volume: this.sfxVolume });
|
||||
} else {
|
||||
// Enhanced placeholder beeps
|
||||
if (key === 'chop') {
|
||||
this.beepChop();
|
||||
} else if (key === 'pickup') {
|
||||
this.beepPickup();
|
||||
} else if (key === 'plant') {
|
||||
this.beepPlant();
|
||||
} else if (key === 'harvest') {
|
||||
this.beepHarvest();
|
||||
} else if (key === 'build') {
|
||||
this.beepBuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
beepChop() {
|
||||
if (!this.scene.sound.context) return;
|
||||
const ctx = this.scene.sound.context;
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
osc.frequency.value = 150;
|
||||
osc.type = 'sawtooth';
|
||||
gain.gain.setValueAtTime(0.15, ctx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.15);
|
||||
osc.start();
|
||||
osc.stop(ctx.currentTime + 0.15);
|
||||
}
|
||||
|
||||
beepPickup() {
|
||||
if (!this.scene.sound.context) return;
|
||||
const ctx = this.scene.sound.context;
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
osc.frequency.setValueAtTime(600, ctx.currentTime);
|
||||
osc.frequency.linearRampToValueAtTime(1200, ctx.currentTime + 0.1);
|
||||
osc.type = 'sine';
|
||||
gain.gain.setValueAtTime(0.12, ctx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.1);
|
||||
osc.start();
|
||||
osc.stop(ctx.currentTime + 0.1);
|
||||
}
|
||||
|
||||
beepPlant() {
|
||||
if (!this.scene.sound.context) return;
|
||||
const ctx = this.scene.sound.context;
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
osc.frequency.value = 300;
|
||||
osc.type = 'triangle';
|
||||
gain.gain.setValueAtTime(0.1, ctx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.12);
|
||||
osc.start();
|
||||
osc.stop(ctx.currentTime + 0.12);
|
||||
}
|
||||
|
||||
beepHarvest() {
|
||||
if (!this.scene.sound.context) return;
|
||||
const ctx = this.scene.sound.context;
|
||||
const osc1 = ctx.createOscillator();
|
||||
const gain1 = ctx.createGain();
|
||||
osc1.connect(gain1);
|
||||
gain1.connect(ctx.destination);
|
||||
osc1.frequency.value = 523;
|
||||
osc1.type = 'sine';
|
||||
gain1.gain.setValueAtTime(0.1, ctx.currentTime);
|
||||
gain1.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.08);
|
||||
osc1.start();
|
||||
osc1.stop(ctx.currentTime + 0.08);
|
||||
|
||||
const osc2 = ctx.createOscillator();
|
||||
const gain2 = ctx.createGain();
|
||||
osc2.connect(gain2);
|
||||
gain2.connect(ctx.destination);
|
||||
osc2.frequency.value = 659;
|
||||
osc2.type = 'sine';
|
||||
gain2.gain.setValueAtTime(0.1, ctx.currentTime + 0.08);
|
||||
gain2.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.16);
|
||||
osc2.start(ctx.currentTime + 0.08);
|
||||
osc2.stop(ctx.currentTime + 0.16);
|
||||
}
|
||||
|
||||
beepBuild() {
|
||||
if (!this.scene.sound.context) return;
|
||||
const ctx = this.scene.sound.context;
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
osc.frequency.value = 80;
|
||||
osc.type = 'square';
|
||||
gain.gain.setValueAtTime(0.2, ctx.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.2);
|
||||
osc.start();
|
||||
osc.stop(ctx.currentTime + 0.2);
|
||||
}
|
||||
|
||||
playAmbient(key, loop = true) {
|
||||
if (this.isMuted) return;
|
||||
if (this.currentAmbient) this.currentAmbient.stop();
|
||||
if (!this.scene.sound.get(key)) return;
|
||||
this.currentAmbient = this.scene.sound.add(key, { volume: this.sfxVolume * 0.5, loop: loop });
|
||||
this.currentAmbient.play();
|
||||
}
|
||||
|
||||
stopAmbient() {
|
||||
if (this.currentAmbient) {
|
||||
this.currentAmbient.stop();
|
||||
this.currentAmbient = null;
|
||||
}
|
||||
}
|
||||
|
||||
toggleMute() {
|
||||
this.isMuted = !this.isMuted;
|
||||
this.scene.sound.mute = this.isMuted;
|
||||
console.log(this.isMuted ? '🔇 Muted' : '🔊 Unmuted');
|
||||
}
|
||||
|
||||
playChop() { this.playSFX('chop'); }
|
||||
playPlant() { this.playSFX('plant'); }
|
||||
playHarvest() { this.playSFX('harvest'); }
|
||||
playBuild() { this.playSFX('build'); }
|
||||
playPickup() { this.playSFX('pickup'); }
|
||||
playRainSound() { this.playAmbient('rain_loop'); }
|
||||
stopRainSound() { this.stopAmbient(); }
|
||||
}
|
||||
Reference in New Issue
Block a user