【问题标题】:Move an object inside a loop that runs 60fps在运行 60fps 的循环内移动对象
【发布时间】:2020-11-20 20:18:23
【问题描述】:

我正在尝试设置一个运行循环,它将每秒执行 60 次——在我的示例中,我想在每次循环运行时简单地将添加一个 px 移动到 div 的左侧位置,但我认为我做错了什么。

在每次循环运行时操作此块的任何帮助都将不胜感激。

function runLoop() {
    var counter = counter + 1;
    var redBlock = document.getElementById("block");
    redBlock.style.left = counter + "px";
}

setInterval(function () {
    runLoop();
}, 60)
#block {
  background-color: red;
  width: 100px;
  height: 100px;
  position: absolute;
  display: block;
}
<div id="block"></block>

【问题讨论】:

  • 是什么让你认为你做错了什么?
  • setInterval 的第二个参数指定调用第一个参数指定的函数之间的间隔(毫秒)。因此,如果您希望每秒调用 60 次(=1000 毫秒),则间隔应为 1000 / 60。
  • 您在每个循环中创建一个新变量,并向其添加 1,而不是在方法“外部”为每个方法调用增加值。

标签: javascript runloop


【解决方案1】:

你不应该对动画使用 setInterval/setTimeout,因为你设置的延迟 X 实际上是“当 X 过去时”。动画也可能发生在屏幕的帧更新之间,这会使动画看起来很卡。

var counter = 0,
    running = true;

function runLoop() {
    counter = counter + 1;
    var redBlock = document.getElementById("block");
    redBlock.style.left = counter + "px";
}

setInterval(function () {
    runLoop();
}, 60)
#block {
  background-color: red;
  width: 100px;
  height: 100px;
  position: absolute;
  display: block;
}
<div id="block"></block>

我建议使用requestAnimationFrame 进行计算,然后等待下一次屏幕更新以绘制新位置。它可能看起来很棘手,但它比看起来更容易,只要你意识到它只是对自身的回调。

我添加了两个按钮,以便您可以玩动画。

请注意与setInterval 相比,动画的流畅程度。

此外,在循环之外进行变量声明以提高性能。

let counter = 0,
    isRunning = true;

const redBlock = document.getElementById("block");

function runLoop() {
  counter = counter + 1;
  redBlock.style.left = counter + "px";
  
  if (isRunning) {
    requestAnimationFrame(runLoop);    
  }
}

function restart() {
  counter = 0;
  
  if (!isRunning) { runLoop(); } 
}

function pause() {
  isRunning = !isRunning;
  
  if (isRunning) { runLoop(); } 
}

requestAnimationFrame(runLoop);
#block {
  background-color: red;
  width: 100px;
  height: 100px;
  position: absolute;
  top: 30px;
  display: block;
}
<div id="block"></div>

<button onclick="pause()">Pause</button>

<button onclick="restart()">Restart</button>

【讨论】:

  • 嘿!谢谢你——奇怪的是,它在 StackOverflow 上运行良好,但是当我尝试在本地运行它时,函数内部没有看到所有全局变量?
  • 会不会是我不小心用let而不是var作为全局变量?
【解决方案2】:

要让函数 runLoop 每秒被调用 60 次,它需要以 (1000 / 60) 毫秒的间隔调用。

另外,counter 需要初始化。

(您还需要一些条件来确定何时停止计数以避免溢出)。

<script>
  function runLoop(xcoord) {
      var redBlock = document.getElementById("block");
      redBlock.style.left = xcoord + "px";
  }

  var counter = 0;
  setInterval(runLoop, 16.7, counter++);

</script>

【讨论】:

    【解决方案3】:

    setInterval 的参数错误,如果要每秒运行 60 次,需要将间隔设置为 1000 / 60。

    现在我猜您正在尝试设置动画循环。您可能想看看为此目的制作的函数。

    requestAnimationFrame(someCallback);
    

    基本上它是一个函数,它将注册一个回调,以便在下一次浏览器渲染调用之前执行。这意味着最多 60 次/秒,但如果浏览器正在努力计算,则可能会更少。

    应用于您的示例,它可能很简单:

    function runLoop() {
          var redBlock = document.getElementById("block");
          redBlock.style.left = xcoord + "px";
          requestAnimationFrame(runLoop()); // register recursivaly a call for next animationFrame
     }
      var counter = 0;
    
      runLoop()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多