Session 4: Sound effects system with Web Audio API

This commit is contained in:
2026-08-20 05:35:16 +00:00
parent 0b72673961
commit f18ef5c396
5 changed files with 159 additions and 3 deletions
+4 -1
View File
@@ -164,7 +164,10 @@ const Achievements = {
if (achievement.condition(Game.state)) {
Game.state.achievements.push(id);
UI.showNotification(`Achievement: ${achievement.name}!`, 'achievement');
// Audio feedback
Audio.playAchievement();
// Particle effect for achievement unlock
const countEl = document.querySelector('#achievements-tab h3');
if (countEl) {
+119
View File
@@ -0,0 +1,119 @@
/**
* Cosmic Garden - Audio System
* Web Audio API-based sound generation (no external assets needed)
*/
const Audio = {
ctx: null,
enabled: true,
/**
* Initialize audio context (must be called after user interaction)
*/
init() {
try {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
this.ctx = new AudioContext();
console.log('🔊 Audio system initialized');
} catch (e) {
console.warn('Web Audio API not supported');
this.enabled = false;
}
},
/**
* Resume audio context (for browsers that suspend it)
*/
resume() {
if (this.ctx && this.ctx.state === 'suspended') {
this.ctx.resume();
}
},
/**
* Create a simple tone
*/
playTone(frequency, duration, type = 'sine', volume = 0.1) {
if (!this.enabled || !this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = type;
osc.frequency.setValueAtTime(frequency, this.ctx.currentTime);
gain.gain.setValueAtTime(volume, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration);
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.start(this.ctx.currentTime);
osc.stop(this.ctx.currentTime + duration);
},
/**
* Play a rising arpeggio (for clicks)
*/
playClick() {
if (!this.enabled) return;
this.resume();
const now = this.ctx.currentTime;
const notes = [523.25, 659.25, 783.99]; // C major chord
notes.forEach((freq, i) => {
setTimeout(() => {
this.playTone(freq, 0.1, 'sine', 0.08);
}, i * 30);
});
},
/**
* Play a purchase sound (descending chime)
*/
playPurchase() {
if (!this.enabled) return;
this.resume();
const notes = [783.99, 659.25, 523.25]; // G - E - C
notes.forEach((freq, i) => {
setTimeout(() => {
this.playTone(freq, 0.15, 'triangle', 0.1);
}, i * 50);
});
},
/**
* Play an achievement unlock fanfare
*/
playAchievement() {
if (!this.enabled) return;
this.resume();
const notes = [523.25, 659.25, 783.99, 1046.50]; // C - E - G - C (high)
notes.forEach((freq, i) => {
setTimeout(() => {
this.playTone(freq, 0.2, 'square', 0.06);
}, i * 80);
});
},
/**
* Play a notification sound
*/
playNotification() {
if (!this.enabled) return;
this.resume();
this.playTone(880, 0.1, 'sine', 0.08);
setTimeout(() => {
this.playTone(1100, 0.15, 'sine', 0.08);
}, 100);
}
};
// Make globally accessible
window.Audio = Audio;
+9 -2
View File
@@ -32,6 +32,7 @@ const Game = {
this.setupEventListeners();
this.startGameLoop();
this.startAutoSave();
Audio.init();
UI.init();
Stats.init();
console.log('🌌 Cosmic Garden initialized!');
@@ -98,7 +99,10 @@ const Game = {
const amount = this.getClickPower();
this.addStardust(amount);
this.state.totalClicks++;
// Audio feedback
Audio.playClick();
// Visual feedback
UI.showFloatingText(event.clientX, event.clientY, `+${this.formatNumber(amount)}`);
Particles.createClickParticles(event.clientX, event.clientY, 8);
@@ -181,7 +185,10 @@ const Game = {
this.state.buildings[buildingId] = (this.state.buildings[buildingId] || 0) + 1;
UI.showNotification(`Bought ${BUILDINGS[buildingId].name}!`, 'success');
// Audio feedback
Audio.playPurchase();
// Particle effect on building purchase
const card = document.getElementById(`building-${buildingId}`);
if (card) {