Javascript 如何停止 requestAnimationFrame 递归/循环?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10735922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:43:31  来源:igfitidea点击:

How to stop a requestAnimationFrame recursion/loop?

javascripthtmlfullscreenwebglthree.js

提问by corazza

I'm using Three.js with the WebGL renderer to make a game which fullscreens when a playlink is clicked. For animation, I use requestAnimationFrame.

我正在使用 Three.js 和 WebGL 渲染器来制作一个play点击链接时全屏显示的游戏。对于动画,我使用requestAnimationFrame.

I initiate it like this:

我是这样启动的:

self.animate = function()
{
    self.camera.lookAt(self.scene.position);

    self.renderer.render(self.scene, self.camera);

    if (self.willAnimate)
        window.requestAnimationFrame(self.animate, self.renderer.domElement);
}

self.startAnimating = function()
{
    self.willAnimate = true;
    self.animate();
}

self.stopAnimating = function()
{
    self.willAnimate = false;
}

When I want to, I call the startAnimatingmethod, and yes, it does work as intended. But, when I call the stopAnimatingfunction, things break! There are no reported errors, though...

当我想要时,我调用该startAnimating方法,是的,它确实按预期工作。但是,当我调用该stopAnimating函数时,事情就坏了!没有报告错误,但...

The setup is basically like this:

设置基本上是这样的:

  • There is a playlink on the page
  • Once the user clicks the link, a renderer's domElementshould fullscreen, and it does
  • The startAnimatingmethod is called and the renderer starts rendering stuff
  • Once escape is clicked, I register an fullscreenchangeevent and execute the stopAnimatingmethod
  • The page tries to exit fullscreen, it does, but the entire document is completely blank
  • play页面上有链接
  • 用户单击链接后,渲染器domElement应该全屏显示,并且确实如此
  • startAnimating方法被调用,渲染器渲染开始东东
  • 单击转义后,我注册一个fullscreenchange事件并执行该stopAnimating方法
  • 页面尝试退出全屏,确实如此,但整个文档完全空白

I'm pretty sure my other code is OK, and that I'm somehow stopping requestAnimationFramein a wrong way. My explanation probably sucked, so I uploaded the code to my website, you can see it happening here: http://banehq.com/Placeholdername/main.html.

我很确定我的其他代码没问题,而且我不知何故requestAnimationFrame以错误的方式停止。我的解释可能很糟糕,所以我将代码上传到我的网站,您可以在这里看到它发生的情况:http: //banehq.com/Placeholdername/main.html

Here is the version where I don't try to call the animation methods, and fullscreening in and out works: http://banehq.com/Correct/Placeholdername/main.html.

这是我不尝试调用动画方法和全屏输入和输出工作的版本:http: //banehq.com/Correct/Placeholdername/main.html

Once playis clicked the first time, the game initializes and it's startmethod is executed. Once the fullscreen exits, the game's stopmethod is executed. Every other time that playhas been clicked, the game only executes it's startmethod, because there is no need for it to be initialized again.

第一次play点击后,游戏初始化并start执行它的方法。一旦全屏退出,游戏的stop方法就会被执行。每隔一次play点击,游戏只执行它的start方法,因为不需要再次初始化它。

Here's how it looks:

这是它的外观:

var playLinkHasBeenClicked = function()
{
    if (!started)
    {
        started = true;

        game = new Game(container); //"container" is an empty div
    }

    game.start();
}

And here's how the startand stopmethods look like:

下面是startstop方法的样子:

self.start = function()
{
    self.container.appendChild(game.renderer.domElement); //Add the renderer's domElement to an empty div
    THREEx.FullScreen.request(self.container);  //Request fullscreen on the div
    self.renderer.setSize(screen.width, screen.height); //Adjust screensize

    self.startAnimating();
}

self.stop = function()
{
    self.container.removeChild(game.renderer.domElement); //Remove the renderer from the div
    self.renderer.setSize(0, 0); //I guess this isn't needed, but welp

    self.stopAnimating();
}

The only difference between this and the working version is that startAnimatingand stopAnimatingmethod callsin startand stopmethods are commented out.

这和工作版本之间的唯一区别是,startAnimatingstopAnimating方法调用startstop方法被注释掉。

采纳答案by corazza

So, after doing some more testing, I've found out that it was, indeed, my other code that posed a problem, not the animation stopping (it was a simple recursion after all). The problem was in dynamically adding and removing the renderer's domElement from the page. After I've stopped doing that, for there was really no reason to do so, and included it once where the initialization was happening, everything started working fine.

因此,在进行了更多测试之后,我发现确实是我的其他代码造成了问题,而不是动画停止(毕竟这是一个简单的递归)。问题在于从页面动态添加和删除渲染器的 domElement。在我停止这样做之后,因为真的没有理由这样做,并且在初始化发生的地方包含它一次,一切都开始正常工作。

回答by gman

One way to start/stop is like this

一种启动/停止方式是这样的

var requestId;

function loop(time) {
    requestId = undefined;

    ...
    // do stuff
    ...

    start();
}

function start() {
    if (!requestId) {
       requestId = window.requestAnimationFrame(loop);
    }
}

function stop() {
    if (requestId) {
       window.cancelAnimationFrame(requestId);
       requestId = undefined;
    }
}

Working example:

工作示例:

const timeElem = document.querySelector("#time");
var requestId;

function loop(time) {
    requestId = undefined;
    
    doStuff(time)
    start();
}

function start() {
    if (!requestId) {
       requestId = window.requestAnimationFrame(loop);
    }
}

function stop() {
    if (requestId) {
       window.cancelAnimationFrame(requestId);
       requestId = undefined;
    }
}

function doStuff(time) {
  timeElem.textContent = (time * 0.001).toFixed(2);
}
  

document.querySelector("#start").addEventListener('click', function() {
  start();
});

document.querySelector("#stop").addEventListener('click', function() {
  stop();
});
<button id="start">start</button>
<button id="stop">stop</button>
<div id="time"></div>

回答by user3363398

Stopping is as simple as not calling requestAnimationFrame anymore, and restarting is to call it it again. ex)

停止就像不再调用 requestAnimationFrame 一样简单,而重新启动就是再次调用它。前任)

        var pause = false;
        function loop(){
                //... your stuff;
                if(pause) return;
                window.requestionAnimationFrame(loop);
        }
       loop(); //to start it off
       pause = true; //to stop it
       loop(); //to restart it

回答by SaikaVA

I played around with the tutorial of a 2D Breakout Gamewhere they also used requestAnimationFrame and I stopped it with a simple return. The return statement ends function execution if the value of return is omitted.

我玩了一个2D Breakout Game的教程,他们也使用了 requestAnimationFrame ,我用一个简单的return停止了它。如果省略 return 的值,则 return 语句结束函数执行。

if(!lives) {
    alert("GAME OVER");
    return;
}

// looping the draw()
requestAnimationFrame(draw);

回答by Neil

I would suggest having a look at the requestAnimationFrame polyfillgibhub page. There are discussions about how this is implemented.

我建议查看requestAnimationFramepolyfill gibhub 页面。有关于如何实施的讨论。