新增聊天室座驾系统
This commit is contained in:
@@ -19,6 +19,10 @@
|
||||
* hearts 爱心飘落(温暖双音)
|
||||
* confetti 彩带庆典(礼炮碎响 + 清亮点缀)
|
||||
* fireflies 萤火虫(稀疏微光铃音)
|
||||
* j35 歼-35 战机(喷气低频 + 高速呼啸 + 音爆扫频)
|
||||
* 99a 99A 主战坦克(履带低频 + 炮击冲击 + 金属震动)
|
||||
* df5c 东风-5C(发射低频 + 尾焰轰鸣 + 高空呼啸)
|
||||
* fujian 福建舰(海浪低频 + 舰载机掠过 + 甲板提示音)
|
||||
*/
|
||||
|
||||
const EffectSounds = (() => {
|
||||
@@ -762,6 +766,385 @@ const EffectSounds = (() => {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动歼-35 战机音效:喷气低频、空中掠过和音爆扫频。
|
||||
*
|
||||
* @returns {Function} 停止函数
|
||||
*/
|
||||
function _startJ35() {
|
||||
const ctx = _getCtx();
|
||||
const master = ctx.createGain();
|
||||
master.gain.value = 0.58;
|
||||
master.connect(ctx.destination);
|
||||
|
||||
const turbine = ctx.createOscillator();
|
||||
const subRumble = ctx.createOscillator();
|
||||
const turbineFilter = ctx.createBiquadFilter();
|
||||
const turbineGain = ctx.createGain();
|
||||
turbine.type = "sawtooth";
|
||||
subRumble.type = "triangle";
|
||||
turbine.frequency.setValueAtTime(72, ctx.currentTime);
|
||||
turbine.frequency.exponentialRampToValueAtTime(210, ctx.currentTime + 1.8);
|
||||
turbine.frequency.exponentialRampToValueAtTime(96, ctx.currentTime + 7.6);
|
||||
subRumble.frequency.setValueAtTime(34, ctx.currentTime);
|
||||
subRumble.frequency.exponentialRampToValueAtTime(68, ctx.currentTime + 1.8);
|
||||
subRumble.frequency.exponentialRampToValueAtTime(38, ctx.currentTime + 7.6);
|
||||
turbineFilter.type = "lowpass";
|
||||
turbineFilter.frequency.setValueAtTime(420, ctx.currentTime);
|
||||
turbineFilter.frequency.exponentialRampToValueAtTime(2600, ctx.currentTime + 1.6);
|
||||
turbineFilter.frequency.exponentialRampToValueAtTime(520, ctx.currentTime + 7.8);
|
||||
turbineGain.gain.setValueAtTime(0.001, ctx.currentTime);
|
||||
turbineGain.gain.linearRampToValueAtTime(0.32, ctx.currentTime + 0.35);
|
||||
turbineGain.gain.linearRampToValueAtTime(0.42, ctx.currentTime + 1.6);
|
||||
turbineGain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 8.1);
|
||||
turbine.connect(turbineFilter);
|
||||
subRumble.connect(turbineFilter);
|
||||
turbineFilter.connect(turbineGain);
|
||||
turbineGain.connect(master);
|
||||
turbine.start(ctx.currentTime);
|
||||
subRumble.start(ctx.currentTime);
|
||||
turbine.stop(ctx.currentTime + 8.2);
|
||||
subRumble.stop(ctx.currentTime + 8.2);
|
||||
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 0.12,
|
||||
duration: 2.6,
|
||||
startFreq: 180,
|
||||
endFreq: 6200,
|
||||
volume: 0.24,
|
||||
q: 0.9,
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 2.05,
|
||||
duration: 0.72,
|
||||
startFreq: 9000,
|
||||
endFreq: 1200,
|
||||
volume: 0.34,
|
||||
q: 1.4,
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 4.2,
|
||||
duration: 1.05,
|
||||
startFreq: 7200,
|
||||
endFreq: 280,
|
||||
volume: 0.2,
|
||||
q: 1.8,
|
||||
filterType: "highpass",
|
||||
});
|
||||
|
||||
[0.42, 0.9, 1.32, 5.1].forEach((delay, index) => {
|
||||
_scheduleTone(ctx, master, {
|
||||
delay,
|
||||
duration: 0.11,
|
||||
freq: [1046.5, 1318.5, 1567.98, 2093][index % 4],
|
||||
endFreq: [1567.98, 1975.53, 2349.32, 3135.96][index % 4],
|
||||
volume: 0.045,
|
||||
type: "square",
|
||||
});
|
||||
});
|
||||
|
||||
const endTimer = setTimeout(() => {
|
||||
master.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.8);
|
||||
setTimeout(() => {
|
||||
try {
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
}, 900);
|
||||
}, 8800);
|
||||
|
||||
return () => {
|
||||
clearTimeout(endTimer);
|
||||
try {
|
||||
master.gain.setValueAtTime(0, ctx.currentTime);
|
||||
turbine.stop();
|
||||
subRumble.stop();
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 99A 主战坦克音效:履带低频、炮击冲击与金属震动。
|
||||
*
|
||||
* @returns {Function} 停止函数
|
||||
*/
|
||||
function _startType99A() {
|
||||
const ctx = _getCtx();
|
||||
const master = ctx.createGain();
|
||||
master.gain.value = 0.52;
|
||||
master.connect(ctx.destination);
|
||||
|
||||
const engine = ctx.createOscillator();
|
||||
const track = ctx.createOscillator();
|
||||
const filter = ctx.createBiquadFilter();
|
||||
const gain = ctx.createGain();
|
||||
engine.type = "sawtooth";
|
||||
track.type = "square";
|
||||
engine.frequency.setValueAtTime(42, ctx.currentTime);
|
||||
engine.frequency.exponentialRampToValueAtTime(68, ctx.currentTime + 1.1);
|
||||
engine.frequency.exponentialRampToValueAtTime(46, ctx.currentTime + 7.5);
|
||||
track.frequency.setValueAtTime(18, ctx.currentTime);
|
||||
track.frequency.linearRampToValueAtTime(24, ctx.currentTime + 2.0);
|
||||
track.frequency.linearRampToValueAtTime(18, ctx.currentTime + 7.5);
|
||||
filter.type = "lowpass";
|
||||
filter.frequency.setValueAtTime(220, ctx.currentTime);
|
||||
filter.frequency.linearRampToValueAtTime(520, ctx.currentTime + 1.4);
|
||||
filter.frequency.linearRampToValueAtTime(260, ctx.currentTime + 7.8);
|
||||
gain.gain.setValueAtTime(0.001, ctx.currentTime);
|
||||
gain.gain.linearRampToValueAtTime(0.32, ctx.currentTime + 0.35);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 8.1);
|
||||
engine.connect(filter);
|
||||
track.connect(filter);
|
||||
filter.connect(gain);
|
||||
gain.connect(master);
|
||||
engine.start(ctx.currentTime);
|
||||
track.start(ctx.currentTime);
|
||||
engine.stop(ctx.currentTime + 8.2);
|
||||
track.stop(ctx.currentTime + 8.2);
|
||||
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 0.2,
|
||||
duration: 2.8,
|
||||
startFreq: 80,
|
||||
endFreq: 420,
|
||||
volume: 0.18,
|
||||
q: 0.8,
|
||||
filterType: "lowpass",
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 4.02,
|
||||
duration: 0.5,
|
||||
startFreq: 180,
|
||||
endFreq: 65,
|
||||
volume: 0.42,
|
||||
q: 0.7,
|
||||
filterType: "lowpass",
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 4.05,
|
||||
duration: 0.18,
|
||||
startFreq: 4800,
|
||||
endFreq: 900,
|
||||
volume: 0.16,
|
||||
q: 1.2,
|
||||
});
|
||||
|
||||
[0.5, 1.1, 1.7, 2.25, 3.0, 3.55, 5.2, 5.85].forEach((delay) => {
|
||||
_scheduleTone(ctx, master, {
|
||||
delay,
|
||||
duration: 0.08,
|
||||
freq: 72,
|
||||
endFreq: 44,
|
||||
volume: 0.045,
|
||||
type: "square",
|
||||
});
|
||||
});
|
||||
|
||||
const endTimer = setTimeout(() => {
|
||||
master.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.8);
|
||||
setTimeout(() => {
|
||||
try {
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
}, 900);
|
||||
}, 8400);
|
||||
|
||||
return () => {
|
||||
clearTimeout(endTimer);
|
||||
try {
|
||||
master.gain.setValueAtTime(0, ctx.currentTime);
|
||||
engine.stop();
|
||||
track.stop();
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动东风-5C预览音效:发射低频、尾焰轰鸣与高空呼啸。
|
||||
*
|
||||
* @returns {Function} 停止函数
|
||||
*/
|
||||
function _startDf5c() {
|
||||
const ctx = _getCtx();
|
||||
const master = ctx.createGain();
|
||||
master.gain.value = 0.58;
|
||||
master.connect(ctx.destination);
|
||||
|
||||
const rumble = ctx.createOscillator();
|
||||
const flame = ctx.createOscillator();
|
||||
const filter = ctx.createBiquadFilter();
|
||||
const gain = ctx.createGain();
|
||||
rumble.type = "sawtooth";
|
||||
flame.type = "triangle";
|
||||
rumble.frequency.setValueAtTime(28, ctx.currentTime);
|
||||
rumble.frequency.exponentialRampToValueAtTime(76, ctx.currentTime + 2.2);
|
||||
rumble.frequency.exponentialRampToValueAtTime(38, ctx.currentTime + 7.4);
|
||||
flame.frequency.setValueAtTime(96, ctx.currentTime);
|
||||
flame.frequency.exponentialRampToValueAtTime(220, ctx.currentTime + 2.8);
|
||||
flame.frequency.exponentialRampToValueAtTime(112, ctx.currentTime + 7.2);
|
||||
filter.type = "lowpass";
|
||||
filter.frequency.setValueAtTime(180, ctx.currentTime);
|
||||
filter.frequency.exponentialRampToValueAtTime(1800, ctx.currentTime + 2.8);
|
||||
filter.frequency.exponentialRampToValueAtTime(420, ctx.currentTime + 7.8);
|
||||
gain.gain.setValueAtTime(0.001, ctx.currentTime);
|
||||
gain.gain.linearRampToValueAtTime(0.4, ctx.currentTime + 0.9);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 8.0);
|
||||
rumble.connect(filter);
|
||||
flame.connect(filter);
|
||||
filter.connect(gain);
|
||||
gain.connect(master);
|
||||
rumble.start(ctx.currentTime);
|
||||
flame.start(ctx.currentTime);
|
||||
rumble.stop(ctx.currentTime + 8.1);
|
||||
flame.stop(ctx.currentTime + 8.1);
|
||||
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 0.08,
|
||||
duration: 3.4,
|
||||
startFreq: 90,
|
||||
endFreq: 2600,
|
||||
volume: 0.28,
|
||||
q: 0.8,
|
||||
filterType: "lowpass",
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 2.1,
|
||||
duration: 2.6,
|
||||
startFreq: 720,
|
||||
endFreq: 8200,
|
||||
volume: 0.22,
|
||||
q: 1.3,
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 4.8,
|
||||
duration: 1.1,
|
||||
startFreq: 9600,
|
||||
endFreq: 1600,
|
||||
volume: 0.18,
|
||||
q: 1.8,
|
||||
filterType: "highpass",
|
||||
});
|
||||
|
||||
[0.2, 0.46, 0.74, 1.04, 1.34].forEach((delay) => {
|
||||
_scheduleTone(ctx, master, {
|
||||
delay,
|
||||
duration: 0.12,
|
||||
freq: 58,
|
||||
endFreq: 32,
|
||||
volume: 0.07,
|
||||
type: "square",
|
||||
});
|
||||
});
|
||||
|
||||
const endTimer = setTimeout(() => {
|
||||
master.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.8);
|
||||
setTimeout(() => {
|
||||
try {
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
}, 900);
|
||||
}, 8500);
|
||||
|
||||
return () => {
|
||||
clearTimeout(endTimer);
|
||||
try {
|
||||
master.gain.setValueAtTime(0, ctx.currentTime);
|
||||
rumble.stop();
|
||||
flame.stop();
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动福建舰预览音效:海浪低频、舰载机掠过与甲板提示音。
|
||||
*
|
||||
* @returns {Function} 停止函数
|
||||
*/
|
||||
function _startFujian() {
|
||||
const ctx = _getCtx();
|
||||
const master = ctx.createGain();
|
||||
master.gain.value = 0.42;
|
||||
master.connect(ctx.destination);
|
||||
|
||||
const engine = ctx.createOscillator();
|
||||
const wake = ctx.createOscillator();
|
||||
const filter = ctx.createBiquadFilter();
|
||||
const gain = ctx.createGain();
|
||||
engine.type = "sawtooth";
|
||||
wake.type = "triangle";
|
||||
engine.frequency.setValueAtTime(38, ctx.currentTime);
|
||||
engine.frequency.exponentialRampToValueAtTime(52, ctx.currentTime + 2.4);
|
||||
engine.frequency.exponentialRampToValueAtTime(34, ctx.currentTime + 8.2);
|
||||
wake.frequency.setValueAtTime(74, ctx.currentTime);
|
||||
wake.frequency.exponentialRampToValueAtTime(92, ctx.currentTime + 2.2);
|
||||
wake.frequency.exponentialRampToValueAtTime(60, ctx.currentTime + 8.2);
|
||||
filter.type = "lowpass";
|
||||
filter.frequency.setValueAtTime(240, ctx.currentTime);
|
||||
filter.frequency.exponentialRampToValueAtTime(720, ctx.currentTime + 2.0);
|
||||
filter.frequency.exponentialRampToValueAtTime(260, ctx.currentTime + 8.4);
|
||||
gain.gain.setValueAtTime(0.001, ctx.currentTime);
|
||||
gain.gain.linearRampToValueAtTime(0.26, ctx.currentTime + 0.55);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 8.6);
|
||||
engine.connect(filter);
|
||||
wake.connect(filter);
|
||||
filter.connect(gain);
|
||||
gain.connect(master);
|
||||
engine.start(ctx.currentTime);
|
||||
wake.start(ctx.currentTime);
|
||||
engine.stop(ctx.currentTime + 8.7);
|
||||
wake.stop(ctx.currentTime + 8.7);
|
||||
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 0.1,
|
||||
duration: 7.8,
|
||||
startFreq: 120,
|
||||
endFreq: 520,
|
||||
volume: 0.18,
|
||||
q: 0.7,
|
||||
filterType: "lowpass",
|
||||
});
|
||||
_scheduleNoiseSweep(ctx, master, {
|
||||
delay: 3.15,
|
||||
duration: 1.35,
|
||||
startFreq: 420,
|
||||
endFreq: 7600,
|
||||
volume: 0.22,
|
||||
q: 1.5,
|
||||
});
|
||||
|
||||
[0.8, 1.35, 2.0, 3.0, 4.7, 5.45].forEach((delay, index) => {
|
||||
_scheduleTone(ctx, master, {
|
||||
delay,
|
||||
duration: 0.12,
|
||||
freq: [880, 1174.66, 1567.98][index % 3],
|
||||
endFreq: [987.77, 1318.51, 1760][index % 3],
|
||||
volume: 0.045,
|
||||
type: "sine",
|
||||
});
|
||||
});
|
||||
|
||||
const endTimer = setTimeout(() => {
|
||||
master.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.8);
|
||||
setTimeout(() => {
|
||||
try {
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
}, 900);
|
||||
}, 9000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(endTimer);
|
||||
try {
|
||||
master.gain.setValueAtTime(0, ctx.currentTime);
|
||||
engine.stop();
|
||||
wake.stop();
|
||||
master.disconnect();
|
||||
} catch (_) {}
|
||||
};
|
||||
}
|
||||
|
||||
// ─── 公开 API ──────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -770,7 +1153,7 @@ const EffectSounds = (() => {
|
||||
* 当 AudioContext 处于 suspended 状态时,先 resume() 再播放,
|
||||
* 解决页面无用户手势时的自动静音问题(如管理员进房自动烟花)。
|
||||
*
|
||||
* @param {string} type 'lightning' | 'fireworks' | 'rain' | 'snow' | 'sakura' | 'meteors' | 'gold-rain' | 'hearts' | 'confetti' | 'fireflies'
|
||||
* @param {string} type 'lightning' | 'fireworks' | 'rain' | 'snow' | 'sakura' | 'meteors' | 'gold-rain' | 'hearts' | 'confetti' | 'fireflies' | 'j35' | '99a' | 'df5c' | 'fujian'
|
||||
*/
|
||||
function play(type) {
|
||||
// 用户开启禁音则跳过
|
||||
@@ -813,6 +1196,18 @@ const EffectSounds = (() => {
|
||||
case "fireflies":
|
||||
_stopFn = _startFireflies();
|
||||
break;
|
||||
case "j35":
|
||||
_stopFn = _startJ35();
|
||||
break;
|
||||
case "99a":
|
||||
_stopFn = _startType99A();
|
||||
break;
|
||||
case "df5c":
|
||||
_stopFn = _startDf5c();
|
||||
break;
|
||||
case "fujian":
|
||||
_stopFn = _startFujian();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user