J'utilise Three.js avec le moteur de rendu WebGL pour créer un jeu qui affiche en plein écran lorsqu'un lien play
est cliqué. Pour l'animation, j'utilise requestAnimationFrame
.
Je l'initie comme ça:
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;
}
Lorsque je le souhaite, j'appelle la méthode startAnimating
et, oui, cela fonctionne comme prévu. Mais lorsque j'appelle la fonction stopAnimating
, les choses se cassent! Il n'y a pas d'erreur signalée, cependant ...
La configuration est fondamentalement comme ceci:
play
sur la pagedomElement
doit être en plein écran, etstartAnimating
est appelée et le moteur de rendu commence le rendufullscreenchange
et exécute la méthode stopAnimating
.Je suis à peu près sûr que mon autre code est correct et que j'arrête en quelque sorte requestAnimationFrame
. Mon explication était probablement nulle, alors j'ai téléchargé le code sur mon site Web, vous pouvez le voir se passer ici: http://banehq.com/Placeholdername/main.html .
Voici la version où je n’essaie pas d’appeler les méthodes d’animation, et le plein écran fonctionne: http://banehq.com/Correct/Placeholdername/main.html .
Une fois que play
est cliqué pour la première fois, le jeu s'initialise et sa méthode start
est exécutée. Une fois le mode plein écran terminé, la méthode stop
du jeu est exécutée. Chaque fois que l'utilisateur clique sur play
, le jeu n'exécute que la méthode start
, car il n'est pas nécessaire de l'initialiser à nouveau.
Voici à quoi ça ressemble:
var playLinkHasBeenClicked = function()
{
if (!started)
{
started = true;
game = new Game(container); //"container" is an empty div
}
game.start();
}
Et voici à quoi ressemblent les méthodes start
et 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();
}
La seule différence entre cette version et la version de travail est que startAnimating
et la méthode stopAnimating
appelle dans start
et les méthodes stop
sont commentées.
Donc, après avoir fait quelques tests supplémentaires, j'ai découvert que c'était bien mon autre code qui posait problème, pas l'arrêt de l'animation (c'était une simple récursion après tout). Le problème tenait à ajouter et à supprimer dynamiquement le domElement du rendu de la page. Après avoir arrêté de le faire, car il n'y avait vraiment aucune raison de le faire, et l'inclure une fois l'initialisation en cours, tout a commencé à bien fonctionner.
Une façon de démarrer/arrêter est comme ça
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;
}
}
Exemple de travail:
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>
Arrêter est aussi simple que de ne plus appeler requestAnimationFrame, et le redémarrer consiste à l'appeler à nouveau. ex)
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
Je suggérerais de jeter un oeil à la page requestAnimationFrame polyfill gibhub. Il y a des discussions sur la façon dont cela est mis en œuvre.
J'ai joué avec le tutoriel d'un 2D Breakout Game où ils ont également utilisé requestAnimationFrame et je l'ai arrêté avec un simple retour . L'instruction return met fin à l'exécution de la fonction si la valeur de return est omise.
if(!lives) {
alert("GAME OVER");
return;
}
// looping the draw()
requestAnimationFrame(draw);