javascript - 如何停止 requestAnimationFrame 递归/循环?

标签 javascript html fullscreen webgl three.js

我将 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();
}

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

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

最佳答案

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

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>

关于javascript - 如何停止 requestAnimationFrame 递归/循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10735922/

相关文章:

android - 如何在 imageView 点击时显示 imageView 全屏?

javascript - DIV 上的 HTML 全屏 API

javascript - 如何找出默认占位符设置

jquery - 选中和取消选中具有不同名称的单选按钮

javascript - 在 div 中并排对齐 block

html - 水平线和图标在一条线上?

html - 在 HTML5 视频上全屏显示时自定义控件仍然适用吗?

javascript - jQuery/JavaScript - 在一个函数完成后启动一个函数?

javascript - Rails 4:如何使用AJAX更新索引页面

javascript - 主干 View 触发事件两次