Browse Source

feat(global): 常驻场景循环播放全局 BGM;Sound 支持 loop/volume

- 移除 init 与各场景对 my-sound 的误停,避免打断 BGM
- BGM 资源路径 public/bg.mp3(需自行放置文件)

Made-with: Cursor
master
npmrun 3 weeks ago
parent
commit
b6050d57fb
  1. 3
      src/init.ts
  2. 16
      src/stages/_global/page_00_global.ts
  3. 4
      src/stages/page_init.ts
  4. 2
      src/stages/welcome/page_welcome.ts
  5. 17
      src/utils/Sound.ts

3
src/init.ts

@ -6,7 +6,6 @@ import { SceneType } from "./enums/SceneType";
import { assetManager } from "./core/AssetManager"; import { assetManager } from "./core/AssetManager";
import { logger } from "./core/Logger"; import { logger } from "./core/Logger";
import eventBus from "./core/EventBus"; import eventBus from "./core/EventBus";
import soundManager from "./utils/Sound";
import { Container } from "pixi.js"; import { Container } from "pixi.js";
const game = Game.getInstance(); const game = Game.getInstance();
@ -18,8 +17,6 @@ export async function initApp(): Promise<void> {
await assetManager.init(); await assetManager.init();
await game.init(); await game.init();
soundManager.add("my-sound", "/bg.mp3", { singleInstance: true, autoPlay: false });
const sceneModules = import.meta.glob("./stages/**/page_*.ts", { eager: true }); const sceneModules = import.meta.glob("./stages/**/page_*.ts", { eager: true });
for (const path in sceneModules) { for (const path in sceneModules) {

16
src/stages/_global/page_00_global.ts

@ -1,8 +1,13 @@
import { logger } from "@/core/Logger"; import { logger } from "@/core/Logger";
import { SceneType } from "@/enums/SceneType"; import { SceneType } from "@/enums/SceneType";
import { BaseScene } from "@/scene/BaseScene"; import { BaseScene } from "@/scene/BaseScene";
import soundManager from "@/utils/Sound";
import { Assets, Container } from "pixi.js"; import { Assets, Container } from "pixi.js";
/** 全局循环 BGM,与业务音效分开命名,避免切场景时被误停 */
const GLOBAL_BGM_ALIAS = "global-bgm";
const GLOBAL_BGM_URL = "/bg.mp3";
export default class Global extends BaseScene { export default class Global extends BaseScene {
stage: Container = new Container(); stage: Container = new Container();
@ -16,6 +21,15 @@ export default class Global extends BaseScene {
Assets.add({ alias: "btn-bg-press", src: "/assets/images/button_square_depth_gradient.png" }); Assets.add({ alias: "btn-bg-press", src: "/assets/images/button_square_depth_gradient.png" });
await Assets.load("btn-bga"); await Assets.load("btn-bga");
await Assets.load("btn-bg-press"); await Assets.load("btn-bg-press");
if (!soundManager.exists(GLOBAL_BGM_ALIAS)) {
soundManager.add(GLOBAL_BGM_ALIAS, GLOBAL_BGM_URL, {
singleInstance: true,
loop: true,
autoPlay: false,
volume: 0.4,
});
}
} }
async layout(): Promise<void> { async layout(): Promise<void> {
@ -37,8 +51,10 @@ export default class Global extends BaseScene {
onLoad(): void { onLoad(): void {
logger.info("Resident scene 00_global onLoad"); logger.info("Resident scene 00_global onLoad");
soundManager.play(GLOBAL_BGM_ALIAS, { loop: true, volume: 0.4 });
} }
onUnLoad(): void { onUnLoad(): void {
soundManager.stop(GLOBAL_BGM_ALIAS);
} }
} }

4
src/stages/page_init.ts

@ -4,7 +4,6 @@ import Game from "@/core/Game";
import { BaseScene } from "@/scene/BaseScene"; import { BaseScene } from "@/scene/BaseScene";
import { SceneType } from "@/enums/SceneType"; import { SceneType } from "@/enums/SceneType";
import position from "@/utils/Position"; import position from "@/utils/Position";
import soundManager from "@/utils/Sound";
import { import {
AnimatedSprite, AnimatedSprite,
Container, Container,
@ -55,6 +54,8 @@ export default class InitScene extends BaseScene {
this.loadingBtn!.textObj.text = this.loadingBtn!.textObj.text =
progress >= 1 ? "即将就绪" : `加载中 ${Math.round(progress * 100)}%`; progress >= 1 ? "即将就绪" : `加载中 ${Math.round(progress * 100)}%`;
}); });
// 延迟3秒
await new Promise(resolve => setTimeout(resolve, 3000));
if (bundle) { if (bundle) {
this.assets = bundle as unknown as Record<string, Texture>; this.assets = bundle as unknown as Record<string, Texture>;
@ -159,7 +160,6 @@ export default class InitScene extends BaseScene {
onUnLoad(): void { onUnLoad(): void {
window.removeEventListener("resize", this.onResize); window.removeEventListener("resize", this.onResize);
soundManager.stop("my-sound");
} }
update(_dt: number, _name: string, ticker: Ticker): void { update(_dt: number, _name: string, ticker: Ticker): void {

2
src/stages/welcome/page_welcome.ts

@ -1,5 +1,4 @@
import Button from "@/components/Button"; import Button from "@/components/Button";
import soundManager from "@/utils/Sound";
import { Container } from "pixi.js"; import { Container } from "pixi.js";
import { BaseScene } from "@/scene/BaseScene"; import { BaseScene } from "@/scene/BaseScene";
import { SceneType } from "@/enums/SceneType"; import { SceneType } from "@/enums/SceneType";
@ -29,7 +28,6 @@ export default class WelcomeScene extends BaseScene {
} }
onUnLoad(): void { onUnLoad(): void {
soundManager.stop("my-sound");
console.log("welcome onUnLoad"); console.log("welcome onUnLoad");
} }
} }

17
src/utils/Sound.ts

@ -9,18 +9,29 @@ class SoundManager {
sound.volumeAll = this.volume; sound.volumeAll = this.volume;
} }
add(name: string, url: string, options?: { singleInstance?: boolean; autoPlay?: boolean }): void { add(
name: string,
url: string,
options?: {
singleInstance?: boolean;
autoPlay?: boolean;
loop?: boolean;
volume?: number;
}
): void {
sound.add(name, { sound.add(name, {
url, url,
singleInstance: options?.singleInstance ?? true, singleInstance: options?.singleInstance ?? true,
autoPlay: options?.autoPlay ?? false, autoPlay: options?.autoPlay ?? false,
loop: options?.loop ?? false,
volume: options?.volume ?? 1,
}); });
logger.debug(`Sound: added "${name}"`); logger.debug(`Sound: added "${name}"`);
} }
play(name: string): void { play(name: string, playOptions?: { loop?: boolean; volume?: number }): void {
if (this.muted) return; if (this.muted) return;
sound.play(name); sound.play(name, playOptions);
} }
stop(name: string): void { stop(name: string): void {

Loading…
Cancel
Save