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
How to stop a requestAnimationFrame recursion/loop?
提问by corazza
I'm using Three.js with the WebGL renderer to make a game which fullscreens when a play
link 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 startAnimating
method, and yes, it does work as intended. But, when I call the stopAnimating
function, things break! There are no reported errors, though...
当我想要时,我调用该startAnimating
方法,是的,它确实按预期工作。但是,当我调用该stopAnimating
函数时,事情就坏了!没有报告错误,但...
The setup is basically like this:
设置基本上是这样的:
- There is a
play
link on the page - Once the user clicks the link, a renderer's
domElement
should fullscreen, and it does - The
startAnimating
method is called and the renderer starts rendering stuff - Once escape is clicked, I register an
fullscreenchange
event and execute thestopAnimating
method - 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 requestAnimationFrame
in 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 play
is clicked the first time, the game initializes and it's start
method is executed. Once the fullscreen exits, the game's stop
method is executed. Every other time that play
has been clicked, the game only executes it's start
method, 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 start
and stop
methods look like:
下面是start
和stop
方法的样子:
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 startAnimating
and stopAnimating
method callsin start
and stop
methods are commented out.
这和工作版本之间的唯一区别是,startAnimating
和stopAnimating
方法调用中start
和stop
方法被注释掉。
采纳答案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 页面。有关于如何实施的讨论。