This commit is contained in:
Your Name
2026-08-11 17:41:36 +08:00
parent cfe4c82c90
commit 03fe4ddf9d
18771 changed files with 3617239 additions and 0 deletions
@@ -0,0 +1,366 @@
"use strict";
const common_vendor = require("../../../common/vendor.js");
const STORAGE_KEY = "tongji_game_sfx_enabled";
const COS = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file";
const SRC = {
tap: `${COS}/20260526/20260526105128557ef8669.mp3`,
swoosh: `${COS}/20260527/202605271539371ebe13672.mp3`,
pop: `${COS}/20260526/202605261051282a0a94508.mp3`,
buzz: `${COS}/20260527/202605271539376ff628472.mp3`,
chime: `${COS}/20260528/202605280937077bad76716.mp3`,
fanfare: `${COS}/20260528/20260528093707b021f5794.mp3`,
blast: `${COS}/20260528/20260528093707ebd4d5733.mp3`,
sparkle: `${COS}/20260528/20260528093707016f07427.mp3`,
stinger: `${COS}/20260528/20260528093709c669f4659.mp3`
};
const SFX = {
// —— 基础素材别名(供分层音效直接调用)——
tap: { src: SRC.tap, volume: 0.32, rate: 1, pool: 3 },
pop: { src: SRC.pop, volume: 0.3, rate: 1, pool: 4 },
fanfare: { src: SRC.fanfare, volume: 0.56, rate: 1, pool: 2 },
blast: { src: SRC.blast, volume: 0.62, rate: 1, pool: 2 },
sparkle: { src: SRC.sparkle, volume: 0.5, rate: 1, pool: 2 },
// —— 交互 ——
select: { src: SRC.tap, volume: 0.32, rate: 1.05, pool: 3 },
deselect: { src: SRC.tap, volume: 0.22, rate: 0.82, pool: 2 },
hint: { src: SRC.tap, volume: 0.26, rate: 1.28, pool: 2 },
swap: { src: SRC.swoosh, volume: 0.38, rate: 1, pool: 3 },
swapFail: { src: SRC.buzz, volume: 0.36, rate: 1.18, pool: 2 },
drop: { src: SRC.pop, volume: 0.3, rate: 0.88, pool: 4 },
dropLight: { src: SRC.pop, volume: 0.22, rate: 1.22, pool: 2 },
// —— 消除(按连数)——
match3: { src: SRC.chime, volume: 0.48, rate: 1, pool: 4 },
match4: { src: SRC.fanfare, volume: 0.54, rate: 1.06, pool: 3 },
match5: { src: SRC.blast, volume: 0.62, rate: 1, pool: 3 },
// —— 消除(按 GI 主色)——
matchLowGi: { src: SRC.chime, volume: 0.42, rate: 0.86, pool: 2 },
matchMidGi: { src: SRC.chime, volume: 0.46, rate: 1.02, pool: 2 },
matchHighGi: { src: SRC.buzz, volume: 0.44, rate: 0.92, pool: 2 },
// —— 连消 ——
combo2: { src: SRC.fanfare, volume: 0.56, rate: 1.12, pool: 2 },
combo3: { src: SRC.blast, volume: 0.64, rate: 1.08, pool: 2 },
comboMega: { src: SRC.blast, volume: 0.72, rate: 1.22, pool: 2 },
// —— 道具 ——
insulin: { src: SRC.sparkle, volume: 0.5, rate: 1.15, pool: 2 },
fiber: { src: SRC.swoosh, volume: 0.48, rate: 1.32, pool: 2 },
meal: { src: SRC.stinger, volume: 0.42, rate: 1.35, pool: 1 },
reshuffle: { src: SRC.swoosh, volume: 0.46, rate: 0.72, pool: 2 },
// —— 反馈 ——
score: { src: SRC.tap, volume: 0.28, rate: 1.38, pool: 2 },
goalTick: { src: SRC.chime, volume: 0.36, rate: 1.45, pool: 2 },
meterWarn: { src: SRC.buzz, volume: 0.5, rate: 1, pool: 2 },
meterDanger: { src: SRC.buzz, volume: 0.58, rate: 0.78, pool: 2 },
meterStable: { src: SRC.pop, volume: 0.24, rate: 1.05, pool: 1 },
win: { src: SRC.fanfare, volume: 0.66, rate: 1, pool: 1 },
winStinger: { src: SRC.stinger, volume: 0.38, rate: 1.5, pool: 1 },
lose: { src: SRC.buzz, volume: 0.52, rate: 0.68, pool: 1 },
// 兼容旧名
match: { src: SRC.chime, volume: 0.48, rate: 1, pool: 4 },
combo: { src: SRC.fanfare, volume: 0.56, rate: 1.1, pool: 3 },
heal: { src: SRC.pop, volume: 0.44, rate: 1.18, pool: 2 },
boost: { src: SRC.sparkle, volume: 0.52, rate: 1, pool: 2 },
invalid: { src: SRC.buzz, volume: 0.4, rate: 1.15, pool: 2 },
danger: { src: SRC.blast, volume: 0.58, rate: 0.95, pool: 2 }
};
const WARMUP_SFX = [
"select",
"swap",
"swapFail",
"drop",
"dropLight",
"match3",
"match4",
"match5",
"combo2",
"combo3",
"comboMega",
"insulin",
"sparkle",
"reshuffle",
"lose"
];
function createAudioContext() {
if (typeof Audio !== "undefined") {
const audio = new Audio();
audio.preload = "auto";
return {
get src() {
return audio.src;
},
set src(value) {
audio.src = value;
},
get volume() {
return audio.volume;
},
set volume(value) {
audio.volume = value;
},
get playbackRate() {
return audio.playbackRate;
},
set playbackRate(value) {
audio.playbackRate = value;
},
play() {
const promise = audio.play();
if (promise == null ? void 0 : promise.catch)
promise.catch(() => {
});
},
stop() {
audio.pause();
try {
audio.currentTime = 0;
} catch (_) {
}
},
seek(time) {
try {
audio.currentTime = time;
} catch (_) {
}
},
destroy() {
audio.pause();
audio.removeAttribute("src");
}
};
}
return common_vendor.index.createInnerAudioContext();
}
class SfxPool {
constructor(src, size, volume, rate = 1) {
this.src = src;
this.size = size;
this.volume = volume;
this.rate = rate;
this.list = [];
this.cursor = 0;
this.warmedUp = false;
}
createOne() {
const ctx = createAudioContext();
ctx.src = this.src;
ctx.obeyMuteSwitch = false;
ctx.autoplay = false;
ctx.volume = this.volume;
try {
ctx.playbackRate = this.rate;
} catch (_) {
}
this.list.push(ctx);
return ctx;
}
create() {
while (this.list.length < this.size)
this.createOne();
}
warmUp() {
if (this.warmedUp)
return;
const ctx = this.list[0] || this.createOne();
try {
ctx.volume = 0;
ctx.play();
setTimeout(() => {
try {
ctx.stop();
ctx.volume = this.volume;
} catch (_) {
}
}, 60);
} catch (_) {
}
if (this.size > 1)
this.cursor = 1;
this.warmedUp = true;
}
play(scale = 1, rateMul = 1) {
if (this.list.length < this.size)
this.create();
const ctx = this.list[this.cursor % this.list.length];
this.cursor += 1;
const vol = Math.min(1, this.volume * scale);
const rate = Math.min(2, Math.max(0.5, this.rate * rateMul));
try {
ctx.volume = vol;
try {
ctx.playbackRate = rate;
} catch (_) {
}
ctx.stop();
ctx.seek(0);
ctx.play();
} catch (_) {
try {
ctx.play();
} catch (e) {
}
}
}
destroy() {
this.list.forEach((ctx) => {
try {
ctx.stop();
ctx.destroy();
} catch (_) {
}
});
this.list = [];
this.warmedUp = false;
}
}
function dominantGi(tiles = []) {
const cnt = { low: 0, mid: 0, high: 0 };
tiles.forEach((t) => {
var _a;
const g = (_a = t == null ? void 0 : t.type) == null ? void 0 : _a.gi;
if (g && cnt[g] !== void 0)
cnt[g] += 1;
});
let best = "mid";
let max = 0;
Object.entries(cnt).forEach(([k, v]) => {
if (v > max) {
max = v;
best = k;
}
});
return best;
}
function useGameSfx() {
const enabled = common_vendor.ref(true);
const pools = {};
try {
const stored = common_vendor.index.getStorageSync(STORAGE_KEY);
if (stored === false || stored === "0" || stored === 0) {
enabled.value = false;
}
} catch (_) {
}
function ensureAudioOption() {
try {
common_vendor.index.setInnerAudioOption({
obeyMuteSwitch: false,
mixWithOther: true
});
} catch (_) {
}
}
function getPool(name) {
const cfg = SFX[name];
if (!cfg)
return null;
if (!pools[name]) {
pools[name] = new SfxPool(cfg.src, cfg.pool, cfg.volume, cfg.rate ?? 1);
}
return pools[name];
}
function warmUp() {
if (!enabled.value)
return;
ensureAudioOption();
const names = typeof Audio !== "undefined" ? ["select"] : WARMUP_SFX;
names.forEach((name) => {
var _a;
(_a = getPool(name)) == null ? void 0 : _a.warmUp();
});
}
function play(name, scale = 1, rateMul = 1) {
var _a;
if (!enabled.value)
return;
(_a = getPool(name)) == null ? void 0 : _a.play(scale, rateMul);
}
function playLayer(primary, secondary, delayMs = 70, secScale = 0.6) {
play(primary);
if (secondary) {
setTimeout(() => play(secondary, secScale), delayMs);
}
}
function playMatch({ matchCount = 3, chain = 0, tiles = [] } = {}) {
if (!enabled.value)
return;
const giTrack = (() => {
const gi = dominantGi(tiles);
if (gi === "low")
return "matchLowGi";
if (gi === "high")
return "matchHighGi";
return "matchMidGi";
})();
if (chain >= 3) {
playLayer("comboMega", giTrack, 90, 0.55);
return;
}
if (chain === 2) {
playLayer("combo3", giTrack, 80, 0.5);
return;
}
if (chain === 1) {
playLayer("combo2", giTrack, 70, 0.45);
return;
}
if (matchCount >= 5) {
playLayer("match5", "matchHighGi", 85, 0.5);
} else if (matchCount >= 4) {
playLayer("match4", giTrack, 65, 0.48);
} else {
play(giTrack, 1, 1);
setTimeout(() => play("match3", 0.85), 40);
}
}
function playDrop(count = 1) {
if (!enabled.value || count <= 0)
return;
const name = count >= 4 ? "drop" : "dropLight";
play(name, Math.min(1.2, 0.85 + count * 0.04), count >= 6 ? 0.9 : 1);
}
function playMeter(delta, level) {
if (!enabled.value)
return;
if (level > 70)
play("meterDanger", 1 + (level - 70) * 0.02);
else if (level < 30)
play("meterWarn", 0.9, 0.95);
else if (delta > 8)
play("meterWarn", 0.75);
else if (delta < -5)
play("meterStable", 1.1);
}
function toggleEnabled() {
enabled.value = !enabled.value;
try {
common_vendor.index.setStorageSync(STORAGE_KEY, enabled.value ? "1" : "0");
} catch (_) {
}
if (enabled.value) {
warmUp();
play("select");
}
}
function destroyAll() {
Object.keys(pools).forEach((key) => {
var _a;
(_a = pools[key]) == null ? void 0 : _a.destroy();
delete pools[key];
});
}
common_vendor.onUnmounted(() => {
destroyAll();
});
return {
enabled,
play,
playLayer,
playMatch,
playDrop,
playMeter,
warmUp,
toggleEnabled,
destroyAll
};
}
exports.useGameSfx = useGameSfx;
//# sourceMappingURL=../../../../.sourcemap/mp-weixin/tongji/endless-game/composables/useGameSfx.js.map