8

我有以下基于画布的游戏的 JS 代码。

var EXPLOSION = "sounds/explosion.wav";

function playSound(str, vol) {
  var snd = new Audio();
  snd.src = str;
  snd.volume = vol;
  snd.play();
}

function createExplosion() {
  playSound(EXPLOSION, 0.5);
}

这可行,但是每次调用它都会发送一个服务器请求以下载声音文件。或者,如果我事先声明了 Audio 对象:

var snd = new Audio();
snd.src = EXPLOSION;
snd.volume = 0.5;

function createExplosion() {
  snd.play();
}

这可行,但是如果在声音播放完毕之前调用 createExplosion 函数,它根本不会播放声音。这意味着一次只允许播放一次声音文件 - 在发生多次爆炸的情况下,它根本不起作用。

有什么方法可以正确播放与自身重叠的音频文件多次?

4

5 回答 5

3

你可以只复制节点cloneNode()play()那个复制节点。

我的音频元素如下所示:

<audio id="knight-audio" src="knight.ogg" preload="auto"></audio>

我有一个onClick听众就是这样做的:

function click() {
    const origAudio = document.getElementById("knight-audio");
    const newAudio = origAudio.cloneNode()
    newAudio.play()
}

由于audio不会显示元素,因此您实际上不必将节点附加到任何东西。

我在客户端和服务器端验证了 Chrome 只尝试下载一次音频文件。

警告:我不确定性能影响,因为在我的网站上,此剪辑的播放次数不会超过页面最大约 40 倍。如果您正在做比这更大的事情,您可能需要清理音频节点?

于 2017-09-04T13:24:20.113 回答
1

尝试这个:

(function() {
    var snds = {};
    window.playSound(str,vol) {
        if( !snds[str]) (snds[str] = new Audio()).src = str;
        snds[str].volume = vol;
        snds[str].play();
    }
})();

然后第一次调用它时它会获取声音,但之后每次它都会重用相同的声音对象。


编辑:您还可以预先加载重复项,以允许声音一次播放不止一次:

(function() {
    var snds = {}
    window.playSound = function(str,vol) {
        if( !snds[str]) {
            snds[str] = [new Audio()];
            snds[str][0].src = str;
        }
        var snd = snds[str], pointer = 0;
        while( snd[pointer].playing) {
            pointer++;
            if( pointer >= snd.length) {
                snd.push(new Audio());
                snd[pointer].src = str;
            }
        }
        snd[pointer].volume = vol;
        snd[pointer].play();
    };
})();

请注意,如果您播放与自身重叠的声音过多,这将发送多个请求,但它应该很快返回 Not Modified,并且只有在您播放的次数比以前多时才会这样做。

于 2013-02-28T01:04:27.340 回答
1

我在我正在构建的俄罗斯方块游戏中寻找这个已经很久了,我认为这个解决方案是最好的。

function playSoundMove() {
  var sound = document.getElementById("move");
  sound.load();     
  sound.play();
}

只需将其加载并准备好即可。

于 2017-08-18T11:20:25.090 回答
0

在我的游戏中,我正在使用预加载,但是在启动声音之后(根本不预加载或在页面加载时预加载所有内容并不那么聪明,某些游戏中根本没有播放一些声音,为什么要加载它们)

const audio {};
audio.dataload = {'entity':false,'entityes':[],'n':0};
audio.dataload.ordernum = function() {
  audio.dataload.n = (audio.dataload.n + 1)%10;
  return audio.dataload.n;
}
audio.dataload.play =  function() {
 
    audio.dataload.entity = new Audio('/some.mp3');
    for (let i = 0; i<10;i++) {
      audio.dataload.entityes.push(audio.dataload.entity.cloneNode());
    }
   
    audio.dataload.entityes[audio.dataload.ordernum()].play();
  
}

audio.dataload.play() // plays sound and preload sounds to memory when it isn't
于 2020-04-08T09:01:42.973 回答
0

更多地依赖内存而不是处理时间,我们可以制作一个包含多个音频克隆的数组,然后按顺序播放它们:

function gameSnd() {
    t = new Audio('sounds/tick.wav');
    v = new Audio('sounds/victory.wav');
    c = 0;
    ticks = [];

    for (var i = 0; i<10;i++)
        ticks.push(t.cloneNode());

    tick = function(){
        c = (c + 1)%10;
        ticks[c].play();
    }

    victory = function(){
        v.play();
    }
}
于 2018-02-12T11:05:00.733 回答