Program Club

requestAnimationFrame 재귀 / 루프를 중지하는 방법은 무엇입니까?

proclub 2020. 11. 23. 20:24
반응형

requestAnimationFrame 재귀 / 루프를 중지하는 방법은 무엇입니까?


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메서드를 호출하면 의도 한대로 작동합니다. 하지만 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>


중지는 더 이상 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

I would suggest having a look at the requestAnimationFrame polyfill gibhub page. 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. 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. The return statement ends function execution if the value of return is omitted.

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

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

참고URL : https://stackoverflow.com/questions/10735922/how-to-stop-a-requestanimationframe-recursion-loop

반응형