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();
}
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
のメソッドcallsがstart
およびstop
メソッドはコメント化されています。
そのため、さらにテストを行ったところ、実際に問題を引き起こしたのはアニメーションの停止ではなく、他のコードであることがわかりました(結局のところ、単純な再帰でした)。問題は、ページからレンダラーのdomElementを動的に追加および削除することでした。私がそれをやめた後、そうする理由は本当になかったし、初期化が起こっていた場所に一度含めたので、すべてがうまくいき始めました。
開始/停止する方法の1つは次のとおりです
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ページをご覧になることをお勧めします。これがどのように実装されるかについての議論があります。
2D Breakout Game のチュートリアルで遊んで、そこでrequestAnimationFrameも使用し、単純な return で停止しました。 returnの値が省略された場合、returnステートメントは関数の実行を終了します。
if(!lives) {
alert("GAME OVER");
return;
}
// looping the draw()
requestAnimationFrame(draw);