[英]How to stop a requestAnimationFrame recursion/loop?
我正在使用 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
函數時,事情就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();
}
下面是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
方法中的調用被注釋掉了。
一種啟動/停止方式是這樣的
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>
停止就像不再調用 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
我建議查看requestAnimationFrame polyfill gibhub 頁面。 有關於如何實施的討論。
因此,在進行了更多測試之后,我發現確實是我的其他代碼造成了問題,而不是動畫停止(畢竟這是一個簡單的遞歸)。 問題在於從頁面動態添加和刪除渲染器的 domElement。 在我停止這樣做之后,因為真的沒有理由這樣做,並且在初始化發生的地方包含它一次,一切都開始正常工作。
我玩了一個2D Breakout Game的教程,他們也使用了 requestAnimationFrame ,我用一個簡單的return停止了它。 如果省略 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)
}
讓我們開始吧
myAnim=requestAnimationFrame(anim)
讓我們停下來
//the cancelation uses the last requestId
cancelAnimationFrame(myAnim)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.