Laya.SoundManager 使用指南

简介

Laya.SoundManager 是 LayaAir 引擎的 声音管理类,用于控制背景音乐和音效的播放。引擎提供两种默认声音方案:WebAudio 和 H5Audio。

声音方案说明

  • 音效播放:优先使用 WebAudio,如不可用则使用 H5Audio
  • 背景音乐:使用 H5Audio(WebAudio 会增加内存占用且需要等待加载完成)
  • 推荐格式:背景音乐使用 mp3,音效使用 wav 或 mp3(打包 APP 时音效只能用 wav)

继承关系

Laya.SoundManager(静态类,无需实例化)

目录


API 参考

音量属性

属性 类型 默认值 说明
musicVolume number 1.0 背景音乐音量(0~1)
soundVolume number 1.0 音效音量(0~1)

静音属性

属性 类型 默认值 说明
muted boolean false 全部静音(音乐+音效)
musicMuted boolean false 背景音乐静音
soundMuted boolean false 音效静音

静态属性

属性 类型 默认值 说明
playbackRate number 1.0 声音播放速率
useAudioMusic boolean true 背景音乐是否使用 Audio 标签
autoStopMusic boolean true 失去焦点后是否自动停止背景音乐

播放方法

方法 参数 返回值 说明
playMusic(url, loops?, complete?, startTime?) 地址, 循环次数, 回调, 起始时间 SoundChannel 播放背景音乐(同时只能有一个)
playSound(url, loops?, complete?, startTime?) 地址, 循环次数, 回调, 起始时间 SoundChannel 播放音效(可同时播放多个)

停止方法

方法 参数 返回值 说明
stopMusic() - void 停止背景音乐
stopSound(url) 声音地址 void 停止指定声音
stopAllSound() - void 停止所有音效
stopAll() - void 停止所有声音(音乐+音效)

工具方法

方法 参数 返回值 说明
findChannel(url) 声音地址 SoundChannel | null 查找声音通道
setMusicVolume(volume) 音量值(0~1) void 设置背景音乐音量(已废弃)
setSoundVolume(volume, url?) 音量值, 地址 void 设置音效音量(已废弃)

基础用法

1. 播放背景音乐

// 播放背景音乐(默认播放一次)
Laya.SoundManager.playMusic("res/music/bgm.mp3");

// 循环播放背景音乐(0 表示无限循环)
Laya.SoundManager.playMusic("res/music/bgm.mp3", 0);

// 播放完成后回调
Laya.SoundManager.playMusic("res/music/bgm.mp3", 1, (success: boolean) => {
    console.log("音乐播放完成:", success);
});

// 从指定时间开始播放(秒)
Laya.SoundManager.playMusic("res/music/bgm.mp3", 1, null, 10);

2. 播放音效

// 播放音效(播放一次)
Laya.SoundManager.playSound("res/sounds/click.mp3");

// 循环播放音效
Laya.SoundManager.playSound("res/sounds/loop.wav", 0);

// 播放完成后回调
Laya.SoundManager.playSound("res/sounds/explosion.mp3", 1, () => {
    console.log("音效播放完成");
});

3. 控制音量

// 设置背景音乐音量(0~1)
Laya.SoundManager.musicVolume = 0.5;

// 设置音效音量(0~1)
Laya.SoundManager.soundVolume = 0.8;

// 获取当前音量
console.log("音乐音量:", Laya.SoundManager.musicVolume);
console.log("音效音量:", Laya.SoundManager.soundVolume);

4. 静音控制

// 全部静音
Laya.SoundManager.muted = true;

// 只静音背景音乐
Laya.SoundManager.musicMuted = true;

// 只静音音效
Laya.SoundManager.soundMuted = true;

// 取消静音
Laya.SoundManager.muted = false;

5. 停止播放

// 停止背景音乐
Laya.SoundManager.stopMusic();

// 停止指定音效
Laya.SoundManager.stopSound("res/sounds/click.mp3");

// 停止所有音效(保留背景音乐)
Laya.SoundManager.stopAllSound();

// 停止所有声音(音乐+音效)
Laya.SoundManager.stopAll();

实用示例

示例1: 基础音效播放器

@regClass()
export class SoundPlayer extends Laya.Script {
    // 点击音效
    public playClick(): void {
        Laya.SoundManager.playSound("res/sounds/click.mp3");
    }

    // 按钮按下音效
    public playButtonDown(): void {
        Laya.SoundManager.playSound("res/sounds/button_down.mp3");
    }

    // 按钮抬起音效
    public playButtonUp(): void {
        Laya.SoundManager.playSound("res/sounds/button_up.mp3");
    }

    // 背景音乐控制
    public playBGM(): void {
        Laya.SoundManager.playMusic("res/music/bgm.mp3", 0);
    }

    public stopBGM(): void {
        Laya.SoundManager.stopMusic();
    }
}

示例2: 游戏音效管理器

@regClass()
export class GameSoundManager extends Laya.Script {
    private static instance: GameSoundManager = null;
    private bgmVolume: number = 0.6;
    private sfxVolume: number = 0.8;

    static getInstance(): GameSoundManager {
        if (!this.instance) {
            this.instance = new GameSoundManager();
        }
        return this.instance;
    }

    onAwake(): void {
        this.init();
    }

    private init(): void {
        // 初始化音量设置
        Laya.SoundManager.musicVolume = this.bgmVolume;
        Laya.SoundManager.soundVolume = this.sfxVolume;
    }

    // 播放背景音乐
    public playBGM(url: string): void {
        Laya.SoundManager.playMusic(url, 0);
    }

    // 停止背景音乐
    public stopBGM(): void {
        Laya.SoundManager.stopMusic();
    }

    // 播放音效
    public playSFX(url: string): void {
        Laya.SoundManager.playSound(url);
    }

    // 设置音乐音量
    public setMusicVolume(volume: number): void {
        this.bgmVolume = Math.max(0, Math.min(1, volume));
        Laya.SoundManager.musicVolume = this.bgmVolume;
    }

    // 设置音效音量
    public setSFXVolume(volume: number): void {
        this.sfxVolume = Math.max(0, Math.min(1, volume));
        Laya.SoundManager.soundVolume = this.sfxVolume;
    }

    // 静音所有声音
    public muteAll(): void {
        Laya.SoundManager.muted = true;
    }

    // 取消静音
    public unmuteAll(): void {
        Laya.SoundManager.muted = false;
        Laya.SoundManager.musicVolume = this.bgmVolume;
        Laya.SoundManager.soundVolume = this.sfxVolume;
    }
}

// 使用示例
let soundMgr = GameSoundManager.getInstance();
soundMgr.playBGM("res/music/battle.mp3");
soundMgr.playSFX("res/sounds/sword.mp3");

示例3: 音量设置面板

@regClass()
export class VolumePanel extends Laya.Sprite {
    private musicSlider: Laya.Sprite;
    private sfxSlider: Laya.Sprite;
    private muteBtn: Laya.Sprite;

    constructor() {
        super();
        this.setupUI();
    }

    private setupUI(): void {
        // 背景音乐音量滑块
        this.musicSlider = this.createSlider("音乐音量", 0.6, (value: number) => {
            Laya.SoundManager.musicVolume = value;
        });
        this.musicSlider.pos(20, 20);
        this.addChild(this.musicSlider);

        // 音效音量滑块
        this.sfxSlider = this.createSlider("音效音量", 0.8, (value: number) => {
            Laya.SoundManager.soundVolume = value;
        });
        this.sfxSlider.pos(20, 80);
        this.addChild(this.sfxSlider);

        // 静音按钮
        this.muteBtn = this.createButton("静音");
        this.muteBtn.pos(20, 140);
        this.muteBtn.on(Laya.Event.CLICK, this, this.toggleMute);
        this.addChild(this.muteBtn);
    }

    private toggleMute(): void {
        Laya.SoundManager.muted = !Laya.SoundManager.muted;
        let label = this.muteBtn.getChildAt(0) as Laya.Text;
        label.text = Laya.SoundManager.muted ? "取消静音" : "静音";
    }

    private createSlider(label: string, value: number, callback: (value: number) => void): Laya.Sprite {
        let container = new Laya.Sprite();

        let text = new Laya.Text();
        text.text = label + ": " + Math.floor(value * 100) + "%";
        text.fontSize = 16;
        text.color = "#FFFFFF";
        container.addChild(text);

        let bg = new Laya.Sprite();
        bg.graphics.drawRect(0, 0, 200, 10, "#666666");
        bg.pos(0, 25);
        container.addChild(bg);

        let fill = new Laya.Sprite();
        fill.graphics.drawRect(0, 0, 200 * value, 10, "#00FF00");
        fill.pos(0, 25);
        container.addChild(fill);

        return container;
    }

    private createButton(label: string): Laya.Sprite {
        let btn = new Laya.Sprite();
        btn.graphics.drawRect(0, 0, 100, 40, "#4488FF");
        btn.size(100, 40);

        let text = new Laya.Text();
        text.text = label;
        text.fontSize = 16;
        text.color = "#FFFFFF";
        text.pos(35, 10);
        btn.addChild(text);

        return btn;
    }
}

示例4: 战斗音效系统

@regClass()
export class BattleSoundSystem extends Laya.Script {
    // 预加载音效资源
    public preloadSounds(): void {
        let sounds = [
            "res/sounds/attack.mp3",
            "res/sounds/hit.mp3",
            "res/sounds/die.mp3",
            "res/sounds/skill.mp3",
            "res/sounds/victory.mp3",
            "res/sounds/defeat.mp3"
        ];

        for (let sound of sounds) {
            Laya.SoundManager.playSound(sound, 0);
            Laya.SoundManager.stopSound(sound);
        }
    }

    // 攻击音效
    public playAttack(): void {
        Laya.SoundManager.playSound("res/sounds/attack.mp3");
    }

    // 受击音效
    public playHit(): void {
        Laya.SoundManager.playSound("res/sounds/hit.mp3");
    }

    // 死亡音效
    public playDie(): void {
        Laya.SoundManager.playSound("res/sounds/die.mp3");
    }

    // 技能音效
    public playSkill(skillId: number): void {
        let soundUrl = "res/sounds/skill" + skillId + ".mp3";
        Laya.SoundManager.playSound(soundUrl);
    }

    // 胜利音乐
    public playVictory(): void {
        Laya.SoundManager.stopMusic();
        Laya.SoundManager.playMusic("res/sounds/victory.mp3", 0);
    }

    // 失败音乐
    public playDefeat(): void {
        Laya.SoundManager.stopMusic();
        Laya.SoundManager.playMusic("res/sounds/defeat.mp3", 0);
    }

    // 停止战斗音效
    public stopBattleSounds(): void {
        Laya.SoundManager.stopAllSound();
    }
}

示例5: 场景音效切换

@regClass()
export class SceneSoundManager extends Laya.Script {
    private currentBGM: string = "";

    // 切换到主菜单场景
    public switchToMainMenu(): void {
        this.playBGM("res/music/main_menu.mp3");
    }

    // 切换到战斗场景
    public switchToBattle(): void {
        this.playBGM("res/music/battle.mp3");
    }

    // 切换到村庄场景
    public switchToVillage(): void {
        this.playBGM("res/music/village.mp3");
    }

    // 播放背景音乐(自动切换)
    private playBGM(url: string): void {
        if (this.currentBGM === url) return;

        this.currentBGM = url;
        Laya.SoundManager.playMusic(url, 0);
    }

    // 淡入背景音乐
    public fadeInBGM(url: string, duration: number = 1): void {
        Laya.SoundManager.musicVolume = 0;
        Laya.SoundManager.playMusic(url, 0);

        let step = 0.1;
        let interval = duration * 1000 / 10;
        let count = 0;
        let totalSteps = 10;

        Laya.timer.loop(interval, this, this.onFadeInTick);

        // 保存引用以便清除
        this._fadeInStep = step;
        this._fadeInTotalSteps = totalSteps;
        this._fadeInCount = 0;
    }

    private _fadeInStep: number = 0.1;
    private _fadeInTotalSteps: number = 10;
    private _fadeInCount: number = 0;

    private onFadeInTick(): void {
        this._fadeInCount++;
        let newVolume = Laya.SoundManager.musicVolume + this._fadeInStep;
        if (this._fadeInCount >= this._fadeInTotalSteps || newVolume >= 0.6) {
            newVolume = 0.6;
            Laya.timer.clear(this, this.onFadeInTick);
        }
        Laya.SoundManager.musicVolume = newVolume;
    }

    // 淡出背景音乐
    public fadeOutBGM(duration: number = 1): void {
        let step = 0.1;
        let interval = duration * 1000 / 10;
        let count = 0;
        let totalSteps = 10;

        Laya.timer.loop(interval, this, this.onFadeOutTick);

        // 保存引用以便清除
        this._fadeOutStep = step;
        this._fadeOutTotalSteps = totalSteps;
        this._fadeOutCount = 0;
    }

    private _fadeOutStep: number = 0.1;
    private _fadeOutTotalSteps: number = 10;
    private _fadeOutCount: number = 0;

    private onFadeOutTick(): void {
        this._fadeOutCount++;
        let newVolume = Laya.SoundManager.musicVolume - this._fadeOutStep;
        if (this._fadeOutCount >= this._fadeOutTotalSteps || newVolume <= 0) {
            newVolume = 0;
            Laya.SoundManager.stopMusic();
            Laya.timer.clear(this, this.onFadeOutTick);
        }
        Laya.SoundManager.musicVolume = newVolume;
    }
}

高级技巧

1. 使用 SoundChannel 控制声音

// 获取 SoundChannel 对象进行精细控制
let channel = Laya.SoundManager.playSound("res/sounds/loop.mp3", 0);

if (channel) {
    // 暂停
    channel.pause();

    // 恢复
    channel.resume();

    // 停止
    channel.stop();

    // 设置音量
    channel.volume = 0.5;

    // 获取播放位置(秒)
    console.log("播放位置:", channel.position);

    // 获取总时长(秒)
    console.log("总时长:", channel.duration);
}

2. 查找并控制正在播放的声音

// 查找指定声音的通道
let channel = Laya.SoundManager.findChannel("res/sounds/explosion.mp3");

if (channel) {
    // 声音正在播放
    console.log("音效正在播放");
    channel.stop();
} else {
    // 声音未播放
    console.log("音效未播放");
    Laya.SoundManager.playSound("res/sounds/explosion.mp3");
}

3. 播放速率控制

// 设置全局播放速率
Laya.SoundManager.playbackRate = 1.5;  // 1.5 倍速
Laya.SoundManager.playbackRate = 0.8;  // 0.8 倍速(慢放)

// 恢复正常速率
Laya.SoundManager.playbackRate = 1.0;

4. 失去焦点处理

// 设置失去焦点后是否自动停止背景音乐
Laya.SoundManager.autoStopMusic = true;   // 自动停止(默认)
Laya.SoundManager.autoStopMusic = false;  // 不自动停止

// 监听焦点变化
Laya.stage.on(Laya.Event.BLUR, this, () => {
    console.log("失去焦点");
});

Laya.stage.on(Laya.Event.FOCUS, this, () => {
    console.log("获得焦点");
    // 可以在这里恢复播放背景音乐
    if (!Laya.SoundManager.autoStopMusic) {
        Laya.SoundManager.playMusic("res/music/bgm.mp3", 0);
    }
});

5. 条件音效播放

@regClass()
export class ConditionalSound extends Laya.Script {
    // 只在音效启用时播放
    public playSoundSafe(url: string): void {
        if (!this.enabled) return;
        if (Laya.SoundManager.soundMuted) return;

        Laya.SoundManager.playSound(url);
    }

    // 播放随机音效
    public playRandomSound(baseName: string, count: number): void {
        if (!this.enabled) return;

        let index = Math.floor(Math.random() * count);
        let url = "res/sounds/" + baseName + index + ".mp3";
        Laya.SoundManager.playSound(url);
    }
}

最佳实践

1. 音量设置建议

场景 音乐音量 音效音量
主菜单 0.6~0.8 0.8~1.0
战斗中 0.4~0.6 0.8~1.0
剧情对话 0.3~0.5 0.6~0.8

2. 音效格式选择

// ✅ 推荐:mp3 格式(兼容性好,文件小)
Laya.SoundManager.playMusic("res/music/bgm.mp3");

// ✅ 推荐:wav 格式(音质好,加载快,适合音效)
Laya.SoundManager.playSound("res/sounds/click.wav");

// ⚠️ 注意:打包 APP 时音效只能用 wav
// H5 网页可以用 mp3

3. 音效预加载

@regClass()
export class SoundPreloader extends Laya.Script {
    // 预加载常用音效(播放后立即停止,加载到缓存)
    public preloadCommonSounds(): void {
        let commonSounds = [
            "res/sounds/click.mp3",
            "res/sounds/close.mp3",
            "res/sounds/open.mp3",
            "res/sounds/confirm.mp3",
            "res/sounds/cancel.mp3"
        ];

        for (let sound of commonSounds) {
            let channel = Laya.SoundManager.playSound(sound);
            if (channel) {
                channel.stop();
            }
        }
    }

    // 在游戏初始化时调用
    onAwake(): void {
        this.preloadCommonSounds();
    }
}

4. 音量持久化

@regClass()
export class SoundSettings extends Laya.Script {
    private static readonly MUSIC_VOLUME_KEY = "musicVolume";
    private static readonly SFX_VOLUME_KEY = "sfxVolume";
    private static readonly MUTED_KEY = "soundMuted";

    // 保存音量设置
    public static saveSettings(): void {
        Laya.LocalStorage.setItem(this.MUSIC_VOLUME_KEY, Laya.SoundManager.musicVolume.toString());
        Laya.LocalStorage.setItem(this.SFX_VOLUME_KEY, Laya.SoundManager.soundVolume.toString());
        Laya.LocalStorage.setItem(this.MUTED_KEY, Laya.SoundManager.muted.toString());
    }

    // 加载音量设置
    public static loadSettings(): void {
        let musicVol = Laya.LocalStorage.getItem(this.MUSIC_VOLUME_KEY);
        let sfxVol = Laya.LocalStorage.getItem(this.SFX_VOLUME_KEY);
        let muted = Laya.LocalStorage.getItem(this.MUTED_KEY);

        if (musicVol) Laya.SoundManager.musicVolume = parseFloat(musicVol);
        if (sfxVol) Laya.SoundManager.soundVolume = parseFloat(sfxVol);
        if (muted) Laya.SoundManager.muted = muted === "true";
    }
}

5. 性能优化

// ❌ 不推荐:每次都创建新的 SoundChannel
onUpdate(): void {
    Laya.SoundManager.playSound("res/sounds/loop.mp3");  // 可能同时播放多个
}

// ✅ 推荐:检查音效是否已在播放
private isPlaying: boolean = false;

playLoopSound(): void {
    if (!this.isPlaying) {
        Laya.SoundManager.playSound("res/sounds/loop.mp3", 0);
        this.isPlaying = true;
    }
}

// ✅ 推荐:场景切换时清理资源
onDestroy(): void {
    Laya.SoundManager.stopAllSound();
    Laya.SoundManager.stopMusic();
}

6. 调试技巧

// 显示声音管理器状态
function debugSoundManager(): void {
    console.log("=== SoundManager 状态 ===");
    console.log("音乐音量:", Laya.SoundManager.musicVolume);
    console.log("音效音量:", Laya.SoundManager.soundVolume);
    console.log("全部静音:", Laya.SoundManager.muted);
    console.log("音乐静音:", Laya.SoundManager.musicMuted);
    console.log("音效静音:", Laya.SoundManager.soundMuted);
    console.log("播放速率:", Laya.SoundManager.playbackRate);
    console.log("自动停止音乐:", Laya.SoundManager.autoStopMusic);
}

// 测试所有音效
let testSounds: string[] = [];
let testIndex: number = 0;

function testAllSounds(): void {
    testSounds = [
        "res/sounds/click.mp3",
        "res/sounds/hit.mp3",
        "res/sounds/explosion.mp3"
    ];
    testIndex = 0;
    Laya.timer.loop(1000, this, onTestTick);
}

function onTestTick(): void {
    if (testIndex < testSounds.length) {
        Laya.SoundManager.playSound(testSounds[testIndex]);
        console.log("测试音效:", testSounds[testIndex]);
        testIndex++;
    } else {
        Laya.timer.clear(this, onTestTick);
    }
}

注意事项

  1. 自动停止:默认情况下失去焦点会自动停止背景音乐(autoStopMusic = true
  2. 音乐独占:同时只能有一个背景音乐在播放,新的音乐会替换旧的
  3. 音效并发:音效可以同时播放多个,注意控制数量避免性能问题
  4. 循环参数loops = 0 表示无限循环,loops = 1 表示播放一次
  5. 完成回调:背景音乐的完成回调参数 successtrue 表示播放完成,false 表示被停止
  6. 音量范围:音量值范围为 0(静音)到 1(最大音量)
  7. 平台兼容:打包 APP 时音效建议使用 wav 格式
  8. 资源释放:使用 stopAll() 后音频资源仍会被缓存,下次播放时直接使用缓存

相关文档

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐