[英]How to stop a requestAnimationFrame recursion/loop?
I'm using Three.js with the WebGL renderer to make a game which fullscreens when a play
link is clicked.我正在使用 Three.js 和 WebGL 渲染器来制作一个点击
play
链接时全屏显示的游戏。 For animation, I use requestAnimationFrame
.对于动画,我使用
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.当我需要时,我会调用
startAnimating
方法,是的,它确实按预期工作。 But, when I call the stopAnimating
function, things break!但是,当我调用
stopAnimating
函数时,事情就stopAnimating
! There are no reported errors, though...没有报告错误,但...
The setup is basically like this:设置基本上是这样的:
play
link on the pageplay
链接domElement
should fullscreen, and it doesdomElement
应全屏显示,并且确实如此startAnimating
method is called and the renderer starts rendering stuff startAnimating
方法被调用,渲染器开始渲染东西fullscreenchange
event and execute the stopAnimating
methodfullscreenchange
事件并执行stopAnimating
方法I'm pretty sure my other code is OK, and that I'm somehow stopping requestAnimationFrame
in a wrong way.我很确定我的其他代码没问题,而且我不知何故以错误的方式停止
requestAnimationFrame
。 My explanation probably sucked, so I uploaded the code to my website, you can see it happening here: http://banehq.com/Placeholdername/main.html .我的解释可能很糟糕,所以我将代码上传到我的网站,您可以在这里看到它发生的情况: 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.一旦第一次点击
play
,游戏就会初始化并执行它的start
方法。 Once the fullscreen exits, the game's stop
method is executed.一旦全屏退出,就会执行游戏的
stop
方法。 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
方法,因为不需要再次初始化它。
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 calls in start
and stop
methods are commented out.此版本与工作版本之间的唯一区别是
startAnimating
和stopAnimating
方法在start
和stop
方法中的调用被注释掉了。
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>
Stopping is as simple as not calling requestAnimationFrame anymore, and restarting is to call it it again.停止就像不再调用 requestAnimationFrame 一样简单,而重新启动就是再次调用它。 ex)
前任)
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
I would suggest having a look at the requestAnimationFrame polyfill gibhub page.我建议查看requestAnimationFrame polyfill gibhub 页面。 There are discussions about how this is implemented.
有关于如何实施的讨论。
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.
问题在于从页面动态添加和删除渲染器的 domElement。 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.
在我停止这样做之后,因为真的没有理由这样做,并且在初始化发生的地方包含它一次,一切都开始正常工作。
I played around with the tutorial of a 2D Breakout Game where they also used requestAnimationFrame and I stopped it with a simple return .我玩了一个2D Breakout Game的教程,他们也使用了 requestAnimationFrame ,我用一个简单的return停止了它。 The return statement ends function execution if the value of return is omitted.
如果省略 return 的值,则 return 语句结束函数执行。
if(!lives) {
alert("GAME OVER");
return;
}
// looping the draw()
requestAnimationFrame(draw);
var myAnim //your requestId
function anim()
{
//bla bla bla
//it's important to update the requestId each time you're calling reuestAnimationFrame
myAnim=requestAnimationFrame(anim)
}
Let's start it让我们开始吧
myAnim=requestAnimationFrame(anim)
Let's stop it让我们停下来
//the cancelation uses the last requestId
cancelAnimationFrame(myAnim)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.