Cómo refrescar una escena en ThreeJS

Cuando estuve jugando con ThreeJS para hacer un pequeño prototipo de un juego, no sabía como refrescar una escena en ThreeJS para reiniciar el nivel, cambiarlo o cargar una partida.

No es complicado pero debes saber algunos puntos.

Prerequisitos

Como sabrás, ThreeJS enlaza una escena a un elemento del DOM y sólo puedes tener 1 escena.

Probablemente tendrás una interfaz, por ejemplo con la salud del personaje:

<div id="game">
  <span id="health" style="position: absolute; top: 5%; left: 5%;"></span></div>

Y tu escena lo usa como contenedor.

Vale, solo podemos tener 1 escena y ya tenemos la UI en un container. Pensemos cómo hacerlo.

Concepto

Una solución sería obtener y usar una copia del contenedor pero:

  • con la interfaz
  • con un ID diferente
  • sin los eventos o vinculaciones de ThreeJS
  • y usarlo como contenedor para la escena

Solución

En el controlador de tu juego, donde inicies la partida, añade:

$('#game').clone() 
  .off() 
  .attr('id','game_scene') 
  .prependTo('body');

Sí, he usado jQuery, no es obligatorio, por supuesto, puedes hacerlo con Javascript plano pero como ya lo estaba usando para alguna animación y resulta útil para el siguiente paso, pensé en reutilizarlo.

Déjame comentar cada función:

  • clone() Obtiene una copia del elemento del DOM
  • off() Elimina todos los eventos vinculados
  • attr() Establece un ID diferente
  • prependTo() Añade la copia al body del documento

Entonces, donde necesites cambiar la escena como para reiniciar el nivel, cambiarlo, cargar partida o lo que sea, añade:

$('#game_scene').remove(); 
var copy = $('#game').clone() 
  .off() 
  .attr('id','game_scene'); 
copy.prependTo('body');

Finalmente, deberías usarlo en tu escena de esta forma

var game_scene = document.getElementById('game_scene');
game_scene.appendChild(scene.renderer.domElement);

Eso es todo, te debería funcionar.

Deja un comentario si necesitas ayuda, tienes alguna pregunta o cualquier sugerencia! 🙂