Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何停止requestAnimationFrame递归/循环?_Javascript_Html_Fullscreen_Webgl_Three.js - Fatal编程技术网

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

Javascript 如何停止requestAnimationFrame递归/循环?,javascript,html,fullscreen,webgl,three.js,Javascript,Html,Fullscreen,Webgl,Three.js,我正在使用带有WebGL渲染器的Three.js制作一个游戏,当点击play链接时,游戏将全屏显示。对于动画,我使用requestAnimationFrame 我是这样开始的: self.animate = function() { self.camera.lookAt(self.scene.position); self.renderer.render(self.scene, self.camera); if (self.willAnimate) w

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

我是这样开始的:

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;
}
当我需要时,我调用
startAnimating
方法,是的,它确实按预期工作。但是,当我调用
stop animating
函数时,一切都中断了!但是,没有报告错误

设置基本上如下所示:

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;
}
  • 页面上有一个
    play
    链接
  • 一旦用户单击该链接,渲染器的
    domeElement
    就会全屏显示,而且它确实会全屏显示
  • 调用
    startAnimating
    方法,渲染器开始渲染内容
  • 单击escape后,我注册一个
    fullscreenchange
    事件,并执行
    stopAnimating
    方法
  • 页面试图全屏退出,但整个文档完全为空
我很确定我的其他代码是正确的,而且我以错误的方式停止了
requestAnimationFrame
。我的解释可能很糟糕,所以我把代码上传到我的网站上,你可以在这里看到它的发生:

以下是我不尝试调用动画方法的版本,全屏输入和输出都有效:

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

下面是它的外观:

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

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

    game.start();
}
下面是
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();
}

此版本与工作版本之间的唯一区别是
startAnimating
stopAnimating
方法调用
start
stop
方法被注释掉。

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

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

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

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;
    }
}
工作示例:

const timeElem=document.querySelector(“时间”);
var请求id;
函数循环(时间){
requestId=未定义;
多斯塔夫(时间)
start();
}
函数start(){
如果(!requestId){
requestId=window.requestAnimationFrame(循环);
}
}
函数停止(){
if(请求ID){
window.cancelAnimationFrame(请求ID);
requestId=未定义;
}
}
函数doStuff(时间){
timeElem.textContent=(time*0.001).toFixed(2);
}
document.querySelector(“#start”).addEventListener('click',function(){
start();
});
document.querySelector(“#stop”).addEventListener('click',function(){
停止();
});
开始
停止

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


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

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

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

这应该是
cancelAnimationFrame
而不是
cancelRequestAnimationFrame
?改变了,尽管在我的辩护中它最初被称为
cancelRequestAnimationFrame
。您可以通过在Chrome中打开控制台并键入
webkitCancel
来验证这一点,您将看到
webkitCancelRequestAnimationFrame
在Chrome 33中仍然存在,这两个函数的文档可以在MDN上找到:(感谢您提供的精彩信息!)关于我发现的东西,不能从函数内部停止循环:这里是a。仅从外部:-)实际上可以从函数内部取消循环,如下所示:
setTimeout(函数(){window.cancelAnimationFrame(requestId);},0)是。这实际上是最简单的方法,但效率不高,因为这样你就必须在每个动画帧内执行检查。我发现cancelAnimationFrame()在繁重的动画循环中执行效率更高。我不明白为什么用户3363398的解决方案比gman的效率低。在gmans解决方案中,在循环中有一个函数调用,然后该函数调用依次执行检查。那不是更重吗?一次检查与函数调用+检查。这将属于@user3363398建议的停止动画帧循环的“不启动下一个循环”方法,另一种方法是使用
cancelAnimationFrame()