【问题标题】:How to coordinate timing for sound and animation如何协调声音和动画的时间
【发布时间】:2017-01-04 23:04:52
【问题描述】:

我正在尝试为这个“乒乓”(fizz-buzz)程序添加声音和动画。我想要发生的是对于数组中的每个项目(数字/ping/pong/pingpong),当声音和动画播放时,文本会在列表中淡入。

我得到的是 - 整个列表一次全部淡入,声音一次播放一个(如果输入的数字很大,它会永远持续下去)但动画只发生一次(显然只是最后一个动画)。

整个项目位于:https://github.com/karenfreemansmith/Epic-AdvancedJSwk1-PingPongCalculator,以及一个指向当前正在运行的页面的链接。 (比下面的代码稍早,只是用新的方式破坏了它。)

我一直在尝试使用 setInterval 和 setTimeout 来同步它们,方法是调用一个函数,该函数一次显示一个元素及其声音和动画:

var play=setInterval(function() {
  var i=1;
  output.forEach(item => {
    showNext(item);
    if(i>=output.length) {
      clearInterval(play);
    }
    i++;
  });
}, 1000);

函数如下所示:

function showNext(item) {
  acorn.style.animation= "";
  acorn.style.webkitAnimation="";
  if(item==="ping") {
    window.setTimeout(playPing(), 1000);
  } else if(item==="pong") {
    window.setTimeout(playPong(), 1000);
  } else if(item==="ping-pong") {
    window.setTimeout(playVolley(), 1000);
  } else {
    window.setTimeout(playMiss(), 1000);
    $("#pingpong").append("<p class='"+item+"'>" + item + "</p>");
  }
}

而且播放功能基本相同,只是声音不同:

function playPing() {
  acorn.style.animation= "ping 1s linear";
  acorn.style.webkitAnimation="ping 1s linear";
  sndSlam1.currentTime = 0;
  sndSlam1.play();
  $("#pingpong").append("<p class='ping'>ping</p>");
}

我想我一定是误解了 setTimeout 的工作原理。为什么动画只播放一次?为什么添加到列表的元素之间没有停顿?

【问题讨论】:

  • 我没有播放音频,只是使用 .mp3 文件播放乒乓球的声音。看起来这里的事件主要是检查文件是否已下载。
  • 获取媒体,然后timeupdateprogress事件可用于确定媒体播放的.currentTime以应用特定样式或动画。
  • 每个声音文件只有一个动画,动画首先播放(或至少开始),然后是所有声音,但没有更多动画。我觉得这很奇怪,因为动画是与 LAST 声音相匹配的动画。看起来还有一个“结束”事件,所以如果我使用 eventListener 和 .then() 来播放动画?
  • 你能创建一个 jsfiddle jsfiddle.net 或 plnkr plnkr.co 来演示吗?

标签: javascript animation audio settimeout setinterval


【解决方案1】:

这里的问题是,是的,您确实有点误解了 setTimeout 的工作原理。

你所做的就是这样称呼它:

window.setTimeout(playVolley(), 1000);

这相当于说:“嘿 JS,立即 执行我的函数 playVolley(因为我使用 () 来指定我想要调用它),然后在 1000 秒内调用它返回的任何内容”。

我强烈怀疑,你真正想做的是:

window.setTimeout(playVolley, 1000);

请注意在 playVolley 之后没有“()”。这相当于说:“嘿 JS,在 1000 秒内执行我的名为 playVolley 的酷函数”。

如果“不带 () 传递函数名”对您来说没有意义,没关系,只需阅读“函数作为一等对象”(例如,here)。这个想法只是任何函数实际上就像一个变量,其中包含一个“函数”,您可以将它传递给任何将“函数”作为输入的东西。例如,setTimeout 确实 - 它需要一个“函数”和一个“整数”设置超时。

但仅解决此问题对您没有帮助。这里还有一个问题:

output.forEach(item => {
  showNext(item);
  ...
}

看,你在这里有效地设置了output.length 超时,所有这些超时一次,在 1000 秒内触发。他们会做什么 - 在 1000 中,所有这些都将同时执行。因此,第一次修复需要解决的问题是,所有动画和声音都不会立即播放,而是会在 1000 毫秒延迟后播放。

我再次强烈怀疑,你想要做的是一个一个地调用output数组的每一步,彼此之间有1000个延迟。

要实现这一点,您需要重构安排通话的方式。您需要将它们链接起来,而不是一次安排它们。一个肮脏但简单的例子是有一个当前动画步骤的索引,当你的 playXXX 完成时,它会安排下一步运行,直到所有步骤都完成。

var currentAnimationStep = 0;
var output = ["ping", "pong", "ping", "pong"];

snowNext(output[currentAnimationStep]);

function showNext(item) {
+  if (item === undefined) {
+    return;
+  }
+
  ...
}

function playPing() {
  acorn.style.animation= "ping 1s linear";
  acorn.style.webkitAnimation="ping 1s linear";
  sndSlam1.currentTime = 0;
  sndSlam1.play();
  $("#pingpong").append("<p class='ping'>ping</p>");

+ currentAnimationStep += 1;
+ showNext(output[currentAnimationStep]);
}

// All other playXXX functions will need the same call added

再一次,这是一个非常肮脏的例子(globals,eeeew),不要告诉任何人我给你展示了这个,但它可以让你开始,当你掌握了闭包时,你会重写它到更易于管理的东西。

【讨论】:

  • 是的,您可能还会遇到一些音频延迟问题,但我认为您不会真的遇到这种情况,无论如何,您会在遇到这些问题时注意(在新的问题,我想)。
  • 我不喜欢全局变量,但效果很好,谢谢!
  • 我也讨厌他们,但这是最简单的开始方式。您还可以添加一些闭包来封装这些步骤,或者使用某些库中的一些链接方法,我想即使是 jQuery 也必须有一些。我对这些库真的不熟悉,有一天我使用“异步”库来做所有这些事情,但当时我眨了几次眼,整个 JS 格局都发生了变化,所以恐怕不能帮不了你。
猜你喜欢
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多