Update game UI, add 3D gear assets, backgrounds, icons, and audio enhancements
This commit is contained in:
+81
-18
@@ -77,10 +77,19 @@ class SoundEngine {
|
||||
// VOLUME & MUTE CONTROLS
|
||||
// ==========================================
|
||||
|
||||
get isMasterMuted() {
|
||||
return this.isMuted;
|
||||
}
|
||||
|
||||
toggleMasterMute() {
|
||||
this.setMasterMute(!this.isMuted);
|
||||
return this.isMuted;
|
||||
}
|
||||
|
||||
setMasterMute(muted) {
|
||||
this.isMuted = muted;
|
||||
this.isMuted = !!muted;
|
||||
if (this.masterGain && this.ctx) {
|
||||
this.masterGain.gain.setTargetAtTime(muted ? 0 : 1.0, this.ctx.currentTime, 0.05);
|
||||
this.masterGain.gain.setTargetAtTime(this.isMuted ? 0 : 1.0, this.ctx.currentTime, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +182,7 @@ class SoundEngine {
|
||||
];
|
||||
|
||||
let step = 0;
|
||||
this.musicInterval = setInterval(() => {
|
||||
const playStep = () => {
|
||||
if (!this.isMusicPlaying || !this.ctx || this.isMuted) return;
|
||||
|
||||
const current = progression[step % progression.length];
|
||||
@@ -247,7 +256,27 @@ class SoundEngine {
|
||||
});
|
||||
|
||||
step++;
|
||||
}, 1800);
|
||||
};
|
||||
|
||||
// Play step 0 immediately with zero delay
|
||||
playStep();
|
||||
this.musicInterval = setInterval(playStep, 1800);
|
||||
}
|
||||
|
||||
enableAudioOnFirstGesture() {
|
||||
const unlockAndPlay = () => {
|
||||
this.ensureContext();
|
||||
if (!this.isMusicPlaying) {
|
||||
this.startBackgroundMusic();
|
||||
}
|
||||
['click', 'keydown', 'pointerdown', 'touchstart'].forEach(evt => {
|
||||
window.removeEventListener(evt, unlockAndPlay);
|
||||
});
|
||||
};
|
||||
|
||||
['click', 'keydown', 'pointerdown', 'touchstart'].forEach(evt => {
|
||||
window.addEventListener(evt, unlockAndPlay, { once: false, passive: true });
|
||||
});
|
||||
}
|
||||
|
||||
stopBackgroundMusic() {
|
||||
@@ -265,6 +294,7 @@ class SoundEngine {
|
||||
setAmbientScenario(scenarioId) {
|
||||
this.ensureContext();
|
||||
this.stopAmbient();
|
||||
this.stopAllTaskSFX();
|
||||
if (!this.ctx || !this.isAmbientEnabled) return;
|
||||
|
||||
if (scenarioId === 'grinding') {
|
||||
@@ -609,19 +639,37 @@ class SoundEngine {
|
||||
|
||||
stopGrinderSFX() {
|
||||
if (this.activeGrinderNode && this.ctx) {
|
||||
const t = this.ctx.currentTime;
|
||||
const node = this.activeGrinderNode;
|
||||
this.activeGrinderNode = null;
|
||||
try {
|
||||
this.activeGrinderNode.gain.gain.linearRampToValueAtTime(0.001, t + 0.1);
|
||||
this.activeGrinderNode.noiseGain.gain.linearRampToValueAtTime(0.001, t + 0.1);
|
||||
const t = this.ctx.currentTime;
|
||||
if (node.gain && node.gain.gain) {
|
||||
node.gain.gain.cancelScheduledValues(t);
|
||||
node.gain.gain.setValueAtTime(node.gain.gain.value, t);
|
||||
node.gain.gain.linearRampToValueAtTime(0.0001, t + 0.05);
|
||||
}
|
||||
if (node.noiseGain && node.noiseGain.gain) {
|
||||
node.noiseGain.gain.cancelScheduledValues(t);
|
||||
node.noiseGain.gain.setValueAtTime(node.noiseGain.gain.value, t);
|
||||
node.noiseGain.gain.linearRampToValueAtTime(0.0001, t + 0.05);
|
||||
}
|
||||
setTimeout(() => {
|
||||
try {
|
||||
this.activeGrinderNode.osc.stop();
|
||||
this.activeGrinderNode.noise.stop();
|
||||
if (node.osc) {
|
||||
node.osc.stop();
|
||||
node.osc.disconnect();
|
||||
}
|
||||
if (node.noise) {
|
||||
node.noise.stop();
|
||||
node.noise.disconnect();
|
||||
}
|
||||
} catch (e) {}
|
||||
this.activeGrinderNode = null;
|
||||
}, 120);
|
||||
}, 60);
|
||||
} catch (e) {
|
||||
this.activeGrinderNode = null;
|
||||
try {
|
||||
if (node.osc) { node.osc.stop(); node.osc.disconnect(); }
|
||||
if (node.noise) { node.noise.stop(); node.noise.disconnect(); }
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -662,21 +710,36 @@ class SoundEngine {
|
||||
|
||||
stopLiquidTransferSFX() {
|
||||
if (this.activeLiquidNode && this.ctx) {
|
||||
const t = this.ctx.currentTime;
|
||||
const node = this.activeLiquidNode;
|
||||
this.activeLiquidNode = null;
|
||||
try {
|
||||
this.activeLiquidNode.gain.gain.linearRampToValueAtTime(0.001, t + 0.1);
|
||||
const t = this.ctx.currentTime;
|
||||
if (node.gain && node.gain.gain) {
|
||||
node.gain.gain.cancelScheduledValues(t);
|
||||
node.gain.gain.setValueAtTime(node.gain.gain.value, t);
|
||||
node.gain.gain.linearRampToValueAtTime(0.0001, t + 0.05);
|
||||
}
|
||||
setTimeout(() => {
|
||||
try {
|
||||
this.activeLiquidNode.noise.stop();
|
||||
if (node.noise) {
|
||||
node.noise.stop();
|
||||
node.noise.disconnect();
|
||||
}
|
||||
} catch (e) {}
|
||||
this.activeLiquidNode = null;
|
||||
}, 120);
|
||||
}, 60);
|
||||
} catch (e) {
|
||||
this.activeLiquidNode = null;
|
||||
try {
|
||||
if (node.noise) { node.noise.stop(); node.noise.disconnect(); }
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stopAllTaskSFX() {
|
||||
this.stopGrinderSFX();
|
||||
this.stopLiquidTransferSFX();
|
||||
}
|
||||
|
||||
playChemicalSplashSFX() {
|
||||
this.ensureContext();
|
||||
if (!this.ctx || this.isMuted) return;
|
||||
|
||||
Reference in New Issue
Block a user