75

我正在使用 Three.js 和 WebGL 渲染器来制作一个在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方法,是的,它确实按预期工作。但是,当我调用该stopAnimating函数时,事情就坏了!虽然没有报告错误...

设置基本上是这样的:

  • 页面上有play链接
  • 用户单击链接后,渲染器domElement应该全屏显示,并且确实如此
  • startAnimating方法被调用并且渲染器开始渲染东西
  • 单击转义后,我注册一个fullscreenchange事件并执行该stopAnimating方法
  • 页面尝试退出全屏,确实如此,但整个文档完全空白

我很确定我的其他代码没问题,而且我以某种requestAnimationFrame错误的方式停止了。我的解释可能很糟糕,所以我将代码上传到我的网站,你可以在这里看到它:http: //banehq.com/Placeholdername/main.html

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

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

这是它的外观:

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

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

    game.start();
}

下面是startandstop方法的样子:

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注释掉了。startstop

4

6 回答 6

137

一种开始/停止的方法是这样的

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("#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>

于 2012-05-25T05:10:54.237 回答
22

停止就像不再调用 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
于 2016-03-29T00:46:47.263 回答
2

我建议看一下requestAnimationFrame polyfill gibhub 页面。有关于如何实施的讨论。

于 2012-05-24T12:25:33.110 回答
2

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

于 2012-05-24T21:16:45.680 回答
2

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

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

// looping the draw()
requestAnimationFrame(draw);
于 2018-09-19T14:38:30.117 回答
1
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)
       }

让我们开始吧

myAnim=requestAnimationFrame(anim)

让我们停下来

//the cancelation uses the last requestId
cancelAnimationFrame(myAnim)

参考

于 2021-08-15T03:35:00.680 回答