Advertisement
  1. Game Development
  2. 3D Games

Creando un juego de corredor sin fin 3D simple usando Three.js

Scroll to top
Read Time: 15 min

() translation by (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

La plataforma web ha tenido un gran crecimiento en los últimos tiempos con la ayuda de HTML5, WebGL y el aumento de la potencia de la generación actual de dispositivos. Ahora los dispositivos móviles y los navegadores son capaces de ofrecer contenido de alto rendimiento tanto en 2D como en 3D. La familiaridad de JavaScript (JS) como lenguaje de scripting también ha sido un factor determinante después de la desaparición de la plataforma web Flash.

La mayoría de los desarrolladores web son conscientes de lo complicado que es el ecosistema de JS con todos los diversos marcos y estándares disponibles, que a veces pueden ser abrumadores para un nuevo desarrollador. Pero cuando se trata de 3D, las opciones son sencillas, gracias a Mr.Doob. Su Three.js es actualmente la mejor opción para crear contenido 3DGL de alto rendimiento. Otra alternativa poderosa es Babylon.js, que también podría usarse para crear juegos en 3D.

En este tutorial, aprenderá a crear un juego de web nativo simple estilo corredor sin fin utilizando el poderoso marco Three.js. Utilizará las teclas de flecha para controlar una bola de nieve rodando por la ladera de una montaña con el fin de esquivar los árboles en su camino. No hay arte involucrado, y todas las imágenes se crean en código.

1. Escena 3D básica

Envato Tuts + ya tiene algunos tutoriales que pueden ayudarlo a comenzar con Three.js. Aquí hay algunos de ellos para que comiences.

Primero crearemos una escena 3D básica, como se muestra aquí donde hay un cubo giratorio. Puede usar la función de arrastrar del mouse para orbitar alrededor del cubo.

Cualquier gráfico que se muestre en una pantalla bidimensional es de naturaleza prácticamente 2D, con algunos elementos importantes que proporcionan la ilusión 3D: la iluminación, el sombreado, las sombras y la magia de proyección 3D a 2D que ocurre a través de la cámara. En la escena anterior, habilitamos la iluminación efectiva usando estas líneas de código.

1
camera = new THREE.PerspectiveCamera( 60, sceneWidth / sceneHeight, 0.1, 1000 );//perspective camera

2
renderer = new THREE.WebGLRenderer({alpha:true});//renderer with transparent backdrop

3
renderer.shadowMap.enabled = true;//enable shadow

4
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
5
6
//...

7
hero = new THREE.Mesh( heroGeometry, heroMaterial );
8
hero.castShadow=true;
9
hero.receiveShadow=false;
10
//...

11
ground.receiveShadow = true;
12
ground.castShadow=false;
13
//..

14
sun = new THREE.DirectionalLight( 0xffffff, 0.8);
15
sun.position.set( 0,4,1 );
16
sun.castShadow = true;
17
scene.add(sun);
18
//Set up shadow properties for the sun light

19
sun.shadow.mapSize.width = 256;
20
sun.shadow.mapSize.height = 256;
21
sun.shadow.camera.near = 0.5;
22
sun.shadow.camera.far = 50 ;

El renderizador necesita tener shadowMap habilitado, la escena necesita tener una luz con castShadow habilitado, y todos los objetos 3D necesitan las propiedades castShadow y receiveShadow establecidas apropiadamente. Para que se produzca el sombreado adecuado, también deberíamos usar MeshStandardMaterial o un material más rico en funciones para nuestros objetos 3D. La cámara se controla con el ingenioso script OrbitControls. Recomiendo jugar con la escena 3D básica agregando formas más primitivas o jugando con la iluminación, etc., antes de continuar con el tutorial.

2. El concepto de Endless Runner

Hay muchos tipos de juegos de corredor sin fin, y el nuestro es un 'rodillo sin fin'. Crearemos un juego donde una bola de nieve rueda por una ladera interminable donde usamos las teclas de flecha para esquivar los árboles entrantes. Una cosa interesante es que este simple juego no involucrará ningún recurso de arte, ya que todos los componentes se crearán por código. Aquí está el juego completo para jugar.

3. Componentes del juego

Los principales componentes o elementos del juego son:

  • la bola de nieve rodando
  • los árboles al azar
  • el campo de desplazamiento
  • la niebla a distancia
  • el efecto de colisión

Exploraremos cada uno de estos uno por uno en la siguiente sección.

La niebla

La niebla es una propiedad de la escena 3D en Tres. Siempre es un truco útil para simular la profundidad o mostrar un horizonte. El color de la niebla es importante para que la ilusión funcione correctamente y depende del color de la escena y la iluminación. Como puede ver en el siguiente código, también configuramos el valor clearColor del renderizador para que se acerque al color de la niebla.

1
scene = new THREE.Scene();
2
scene.fog = new THREE.FogExp2( 0xf0fff0, 0.14 );
3
camera = new THREE.PerspectiveCamera( 60, sceneWidth / sceneHeight, 0.1, 1000 );//perspective camera

4
renderer = new THREE.WebGLRenderer({alpha:true});//renderer with transparent backdrop

5
renderer.setClearColor(0xfffafa, 1); 

Para que coincida con el ambiente, también estamos utilizando valores de color similares a las luces utilizadas en la escena. Cada color ambiental es un tono diferente de blanco que se gelifica para crear el efecto necesario.

1
var hemisphereLight = new THREE.HemisphereLight(0xfffafa,0x000000, .9)
2
scene.add(hemisphereLight);
3
sun = new THREE.DirectionalLight( 0xcdc1c5, 0.9);
4
sun.position.set( 12,6,-7 );
5
sun.castShadow = true;
6
scene.add(sun);

La bola de nieve

Nuestra bola de nieve es una forma primitiva DodecahedronGeometry creada como se muestra a continuación.

1
var sphereGeometry = new THREE.DodecahedronGeometry( heroRadius, 1);
2
var sphereMaterial = new THREE.MeshStandardMaterial( { color: 0xe5f2f2 ,shading:THREE.FlatShading} )
3
heroSphere = new THREE.Mesh( sphereGeometry, sphereMaterial );

Para todos los elementos 3D de este juego, estamos usando THREE.FlatShading para obtener el aspecto deseado de baja poli.

La montaña de desplazamiento

El campo de desplazamiento llamado rollingGroundSphere es una gran primitiva de SphereGeometry, y lo rotamos en el eje x para crear la ilusión de suelo en movimiento. La bola de nieve realmente no rueda sobre nada; solo estamos creando la ilusión manteniendo la esfera terrestre rodando mientras mantenemos la bola de nieve inmóvil.

Una esfera primitiva normal se verá muy suave y, por lo tanto, no proporcionará la robustez necesaria para la pendiente de la montaña. Así que hacemos algunas manipulaciones de vértices para cambiar la superficie lisa de la esfera en un terreno accidentado. Aquí está el código correspondiente seguido de una explicación.

1
var sides=40;
2
var tiers=40;
3
var sphereGeometry = new THREE.SphereGeometry( worldRadius, sides,tiers);
4
var sphereMaterial = new THREE.MeshStandardMaterial( { color: 0xfffafa ,shading:THREE.FlatShading} )
5
var vertexIndex;
6
var vertexVector= new THREE.Vector3();
7
var nextVertexVector= new THREE.Vector3();
8
var firstVertexVector= new THREE.Vector3();
9
var offset= new THREE.Vector3();
10
var currentTier=1;
11
var lerpValue=0.5;
12
var heightValue;
13
var maxHeight=0.07;
14
for(var j=1;j<tiers-2;j++){
15
  currentTier=j;
16
	for(var i=0;i<sides;i++){
17
		vertexIndex=(currentTier*sides)+1;
18
		vertexVector=sphereGeometry.vertices[i+vertexIndex].clone();
19
		if(j%2!==0){
20
			if(i===0){
21
				firstVertexVector=vertexVector.clone();
22
			}
23
			nextVertexVector=sphereGeometry.vertices[i+vertexIndex+1].clone();
24
			if(i==sides-1){
25
				nextVertexVector=firstVertexVector;
26
			}
27
			lerpValue=(Math.random()*(0.75-0.25))+0.25;
28
			vertexVector.lerp(nextVertexVector,lerpValue);
29
		}
30
		heightValue=(Math.random()*maxHeight)-(maxHeight/2);
31
		offset=vertexVector.clone().normalize().multiplyScalar(heightValue);
32
		sphereGeometry.vertices[i+vertexIndex]=(vertexVector.add(offset));
33
	}
34
}
35
rollingGroundSphere = new THREE.Mesh( sphereGeometry, sphereMaterial );

Estamos creando una esfera primitiva con 40 segmentos horizontales (lados) y 40 segmentos verticales (niveles). Se puede acceder a cada vértice de una geometría de tres a través de la propiedad de matriz vértices. Recorrimos todos los niveles entre los vértices extremos superior e inferior para hacer nuestras manipulaciones de vértices. Cada nivel de la geometría de la esfera contiene exactamente el mismo  número sides de vértices, que forma un anillo cerrado alrededor de la esfera.

El primer paso es rotar cada anillo impar de vértices para romper la uniformidad de los contornos de la superficie. Movemos cada vértice en el anillo por una fracción aleatoria entre 0.25 y 0.75 de la distancia al siguiente vértice. Como resultado de esto, los vértices verticales de la esfera ya no están alineados en línea recta, y obtenemos un bonito contorno en zigzag.

Como segundo paso, proporcionamos a cada vértice un ajuste de altura aleatorio alineado con el normal en el vértice, independientemente del nivel al que pertenece. Esto da como resultado una superficie desigual y rugosa. Espero que las matemáticas vectoriales utilizadas aquí sean sencillas una vez que consideras que el centro de la esfera se considera el origen (0,0).

Los árboles

Los árboles aparecen fuera de nuestra pista rodante para agregar profundidad al mundo y dentro como obstáculos. Crear el árbol es un poco más complicado que el terreno accidentado, pero sigue la misma lógica. Utilizamos una primitiva ConeGeometry para crear la parte verde superior del árbol y un CylinderGeometry para crear la parte inferior del tronco.

Para la parte superior, recorremos cada nivel de los vértices y expandimos el anillo de vértices seguido de la reducción del siguiente anillo. El siguiente código muestra el método blowUpTree utilizado para expandir el anillo alternativo de vértices hacia afuera y el método tightenTree utilizado para reducir el siguiente anillo de vértices.

1
function createTree(){
2
    var sides=8;
3
	var tiers=6;
4
	var scalarMultiplier=(Math.random()*(0.25-0.1))+0.05;
5
	var midPointVector= new THREE.Vector3();
6
	var vertexVector= new THREE.Vector3();
7
	var treeGeometry = new THREE.ConeGeometry( 0.5, 1, sides, tiers);
8
	var treeMaterial = new THREE.MeshStandardMaterial( { color: 0x33ff33,shading:THREE.FlatShading  } );
9
	var offset;
10
	midPointVector=treeGeometry.vertices[0].clone();
11
	var currentTier=0;
12
	var vertexIndex;
13
	blowUpTree(treeGeometry.vertices,sides,0,scalarMultiplier);
14
	tightenTree(treeGeometry.vertices,sides,1);
15
	blowUpTree(treeGeometry.vertices,sides,2,scalarMultiplier*1.1,true);
16
	tightenTree(treeGeometry.vertices,sides,3);
17
	blowUpTree(treeGeometry.vertices,sides,4,scalarMultiplier*1.2);
18
	tightenTree(treeGeometry.vertices,sides,5);
19
	var treeTop = new THREE.Mesh( treeGeometry, treeMaterial );
20
	treeTop.castShadow=true;
21
	treeTop.receiveShadow=false;
22
	treeTop.position.y=0.9;
23
	treeTop.rotation.y=(Math.random()*(Math.PI));
24
	var treeTrunkGeometry = new THREE.CylinderGeometry( 0.1, 0.1,0.5);
25
	var trunkMaterial = new THREE.MeshStandardMaterial( { color: 0x886633,shading:THREE.FlatShading  } );
26
	var treeTrunk = new THREE.Mesh( treeTrunkGeometry, trunkMaterial );
27
	treeTrunk.position.y=0.25;
28
	var tree =new THREE.Object3D();
29
	tree.add(treeTrunk);
30
	tree.add(treeTop);
31
	return tree;
32
}
33
function blowUpTree(vertices,sides,currentTier,scalarMultiplier,odd){
34
	var vertexIndex;
35
	var vertexVector= new THREE.Vector3();
36
	var midPointVector=vertices[0].clone();
37
	var offset;
38
	for(var i=0;i<sides;i++){
39
		vertexIndex=(currentTier*sides)+1;
40
		vertexVector=vertices[i+vertexIndex].clone();
41
		midPointVector.y=vertexVector.y;
42
		offset=vertexVector.sub(midPointVector);
43
		if(odd){
44
			if(i%2===0){
45
				offset.normalize().multiplyScalar(scalarMultiplier/6);
46
				vertices[i+vertexIndex].add(offset);
47
			}else{
48
				offset.normalize().multiplyScalar(scalarMultiplier);
49
				vertices[i+vertexIndex].add(offset);
50
				vertices[i+vertexIndex].y=vertices[i+vertexIndex+sides].y+0.05;
51
			}
52
		}else{
53
			if(i%2!==0){
54
				offset.normalize().multiplyScalar(scalarMultiplier/6);
55
				vertices[i+vertexIndex].add(offset);
56
			}else{
57
				offset.normalize().multiplyScalar(scalarMultiplier);
58
				vertices[i+vertexIndex].add(offset);
59
				vertices[i+vertexIndex].y=vertices[i+vertexIndex+sides].y+0.05;
60
			}
61
		}
62
	}
63
}
64
function tightenTree(vertices,sides,currentTier){
65
	var vertexIndex;
66
	var vertexVector= new THREE.Vector3();
67
	var midPointVector=vertices[0].clone();
68
	var offset;
69
	for(var i=0;i<sides;i++){
70
		vertexIndex=(currentTier*sides)+1;
71
		vertexVector=vertices[i+vertexIndex].clone();
72
		midPointVector.y=vertexVector.y;
73
		offset=vertexVector.sub(midPointVector);
74
		offset.normalize().multiplyScalar(0.06);
75
		vertices[i+vertexIndex].sub(offset);
76
	}
77
}

El método blowUpTree empuja cada vértice alternativo en un anillo de vértices mientras mantiene los otros vértices en el anillo a una menor altura. Esto crea las ramas puntiagudas en el árbol. Si usamos los vértices impares en un nivel, entonces usamos los vértices pares en el siguiente nivel para que la uniformidad se rompa. Una vez que se forma el árbol completo, le damos una rotación aleatoria en el eje Y para que se vea ligeramente diferente.

El efecto de explosión

El efecto de explosión de píxeles en bloque no es el más elegante que podríamos usar, pero ciertamente funciona bien. Este efecto de partícula particular es en realidad una geometría 3D que se manipula para que parezca un efecto utilizando la clase THREE.Points.

1
function addExplosion(){
2
    particleGeometry = new THREE.Geometry();
3
	for (var i = 0; i < particleCount; i ++ ) {
4
		var vertex = new THREE.Vector3();
5
		particleGeometry.vertices.push( vertex );
6
	}
7
	var pMaterial = new THREE.ParticleBasicMaterial({
8
	  color: 0xfffafa,
9
	  size: 0.2
10
	});
11
	particles = new THREE.Points( particleGeometry, pMaterial );
12
	scene.add( particles );
13
	particles.visible=false;
14
}
15
function explode(){
16
	particles.position.y=2;
17
	particles.position.z=4.8;
18
	particles.position.x=heroSphere.position.x;
19
	for (var i = 0; i < particleCount; i ++ ) {
20
		var vertex = new THREE.Vector3();
21
		vertex.x = -0.2+Math.random() * 0.4;
22
		vertex.y = -0.2+Math.random() * 0.4 ;
23
		vertex.z = -0.2+Math.random() * 0.4;
24
		particleGeometry.vertices[i]=vertex;
25
	}
26
	explosionPower=1.07;
27
	particles.visible=true;
28
}
29
function doExplosionLogic(){//called in update

30
    if(!particles.visible)return;
31
    for (var i = 0; i < particleCount; i ++ ) {
32
		particleGeometry.vertices[i].multiplyScalar(explosionPower);
33
	}
34
	if(explosionPower>1.005){
35
		explosionPower-=0.001;
36
	}else{
37
		particles.visible=false;
38
	}
39
	particleGeometry.verticesNeedUpdate = true;
40
}

El método addExplosion agrega 20 vértices a la matriz de vértices de particleGeometry. El método de explosión se invoca cuando necesitamos que se ejecute el efecto, que coloca aleatoriamente cada vértice de la geometría. Se llama a doExplosionLogic en el método de actualización si el objeto de partícula es visible, donde movemos cada vértice hacia afuera. Cada vértice en un objeto de puntos se representa como un bloque cuadrado.

4. El juego

Ahora que sabemos cómo crear cada uno de los elementos necesarios para el juego, entremos en el juego. Los principales elementos del juego son:

  • el bucle del juego
  • la ubicación de los árboles
  • la interacción del usuario
  • la detección de colisión

Analicemos esos en detalle.

El bucle del juego

Toda la mecánica básica del juego ocurre en el ciclo del juego, que en nuestro caso es el método de actualización. Lo llamamos por primera vez desde el método init, que recibe un llamado en la carga de la ventana. Después de esto, se engancha en el bucle de procesamiento de documentos utilizando el método requestAnimationFrame para que se llame repetidamente.

1
function update(){
2
    rollingGroundSphere.rotation.x += rollingSpeed;
3
    heroSphere.rotation.x -= heroRollingSpeed;
4
    if(heroSphere.position.y<=heroBaseY){
5
        jumping=false;
6
    	bounceValue=(Math.random()*0.04)+0.005;
7
    }
8
    heroSphere.position.y+=bounceValue;
9
    heroSphere.position.x=THREE.Math.lerp(heroSphere.position.x,currentLane, 2*clock.getDelta());//clock.getElapsedTime());

10
    bounceValue-=gravity;
11
    if(clock.getElapsedTime()>treeReleaseInterval){
12
    	clock.start();
13
    	addPathTree();
14
    	if(!hasCollided){
15
            score+=2*treeReleaseInterval;
16
            scoreText.innerHTML=score.toString();
17
        }
18
    }
19
    doTreeLogic();
20
    doExplosionLogic();
21
    render();
22
    requestAnimationFrame(update);//request next update

23
}
24
function render(){
25
    renderer.render(scene, camera);//draw

26
}

En la actualización, llamamos al método de renderizado, que usa el renderizador para dibujar la escena. Llamamos al método doTreeLogic, que comprueba la colisión y también elimina los árboles una vez que se han perdido de vista.

La bola de nieve y las esferas de tierra giran mientras también agregamos una lógica de rebote al azar a la bola de nieve. Los árboles nuevos se colocan en la ruta llamando a addPathTree después de que haya transcurrido un tiempo predefinido. El tiempo se rastrea utilizando un objeto THREE.Clock. También actualizamos el puntaje a menos que haya ocurrido una colisión.

Colocación de los árboles

Un conjunto de árboles se coloca fuera de la pista rodante para crear el mundo utilizando el método addWorldTrees. Todos los árboles se agregan como elementos secundarios de rollingGroundSphere para que también se muevan cuando rotamos la esfera.

1
function addWorldTrees(){
2
    var numTrees=36;
3
	var gap=6.28/36;
4
	for(var i=0;i<numTrees;i++){
5
		addTree(false,i*gap, true);
6
		addTree(false,i*gap, false);
7
	}
8
}
9
function addTree(inPath, row, isLeft){
10
	var newTree;
11
	if(inPath){
12
		if(treesPool.length===0)return;
13
		newTree=treesPool.pop();
14
		newTree.visible=true;
15
		//console.log("add tree");

16
		treesInPath.push(newTree);
17
		sphericalHelper.set( worldRadius-0.3, pathAngleValues[row], -rollingGroundSphere.rotation.x+4 );
18
	}else{
19
		newTree=createTree();
20
		var forestAreaAngle=0;//[1.52,1.57,1.62];

21
		if(isLeft){
22
			forestAreaAngle=1.68+Math.random()*0.1;
23
		}else{
24
			forestAreaAngle=1.46-Math.random()*0.1;
25
		}
26
		sphericalHelper.set( worldRadius-0.3, forestAreaAngle, row );
27
	}
28
	newTree.position.setFromSpherical( sphericalHelper );
29
	var rollingGroundVector=rollingGroundSphere.position.clone().normalize();
30
	var treeVector=newTree.position.clone().normalize();
31
	newTree.quaternion.setFromUnitVectors(treeVector,rollingGroundVector);
32
	newTree.rotation.x+=(Math.random()*(2*Math.PI/10))+-Math.PI/10;
33
	
34
	rollingGroundSphere.add(newTree);
35
}

Para plantar árboles del mundo, llamamos al método addTree al pasar valores alrededor de la circunferencia de nuestra esfera terrestre. La utilidad esféricaHelper nos ayuda a encontrar la posición en la superficie de una esfera.

Para plantar árboles en el camino, haremos uso de un grupo de árboles que se crean al comenzar usando el método createTreesPool. También tenemos valores de ángulos predefinidos para cada ruta en la esfera almacenada en la matriz pathAngleValues.

1
pathAngleValues=[1.52,1.57,1.62];
2
//..

3
function createTreesPool(){
4
    var maxTreesInPool=10;
5
	var newTree;
6
	for(var i=0; i<maxTreesInPool;i++){
7
		newTree=createTree();
8
		treesPool.push(newTree);
9
	}
10
}
11
function addPathTree(){
12
    var options=[0,1,2];
13
	var lane= Math.floor(Math.random()*3);
14
	addTree(true,lane);
15
	options.splice(lane,1);
16
	if(Math.random()>0.5){
17
		lane= Math.floor(Math.random()*2);
18
		addTree(true,options[lane]);
19
	}
20
}

El método addPathTree se llama a partir de la actualización cuando ha transcurrido el tiempo suficiente después de plantar el último árbol. A su vez llama al método addTree mostrado anteriormente con un conjunto diferente de parámetros donde el árbol se coloca en la ruta seleccionada. El método doTreeLogic devolverá el árbol al grupo una vez que se salga de la vista.

La interacción del usuario

Estamos agregando un oyente al documento para buscar eventos de teclado relevantes. El método handleKeyDown establece el valor del currentLane si se presionan las teclas de flecha derecha o izquierda o establece el valor de bounceValue si se presiona la flecha hacia arriba.

1
document.onkeydown = handleKeyDown;
2
//..

3
function handleKeyDown(keyEvent){
4
    if(jumping)return;
5
	var validMove=true;
6
	if ( keyEvent.keyCode === 37) {//left

7
		if(currentLane==middleLane){
8
			currentLane=leftLane;
9
		}else if(currentLane==rightLane){
10
			currentLane=middleLane;
11
		}else{
12
			validMove=false;	
13
		}
14
	} else if ( keyEvent.keyCode === 39) {//right

15
		if(currentLane==middleLane){
16
			currentLane=rightLane;
17
		}else if(currentLane==leftLane){
18
			currentLane=middleLane;
19
		}else{
20
			validMove=false;	
21
		}
22
	}else{
23
		if ( keyEvent.keyCode === 38){//up, jump

24
			bounceValue=0.1;
25
			jumping=true;
26
		}
27
		validMove=false;
28
	}
29
    if(validMove){
30
		jumping=true;
31
		bounceValue=0.06;
32
	}
33
}

En la actualización, la posición x de nuestra bola de nieve se incrementa lentamente para alcanzar la currentLane allí al cambiar de carril.

Detección de colisiones

No hay física real involucrada en este juego en particular, aunque podríamos usar varios marcos físicos para nuestro propósito de detección de colisión. Pero como usted bien sabe, un motor de física agrega mucho rendimiento a nuestro juego, y siempre debemos tratar de ver si podemos evitarlo.

En nuestro caso, calculamos la distancia entre nuestra bola de nieve y cada árbol para provocar una colisión si están muy cerca. Esto sucede en el método doTreeLogic, que se llama desde la actualización.

1
function doTreeLogic(){
2
    var oneTree;
3
	var treePos = new THREE.Vector3();
4
	treesInPath.forEach( function ( element, index ) {
5
		oneTree=treesInPath[ index ];
6
		treePos.setFromMatrixPosition( oneTree.matrixWorld );
7
		if(treePos.distanceTo(heroSphere.position)<=0.6){
8
			console.log("hit");
9
			hasCollided=true;
10
			explode();
11
		}
12
	});
13
    //..

14
}

Como habrás notado, todos los árboles actualmente presentes en nuestra ruta se almacenan en la matriz treesInPath. El método doTreeLogic también elimina los árboles de la pantalla y en el grupo una vez que salen de nuestra vista utilizando el código que se muestra a continuación.

1
var treesToRemove=[];
2
treesInPath.forEach( function ( element, index ) {
3
	oneTree=treesInPath[ index ];
4
	treePos.setFromMatrixPosition( oneTree.matrixWorld );
5
	if(treePos.z>6 &&oneTree.visible){//gone out of our view zone

6
		treesToRemove.push(oneTree);
7
	}
8
});
9
var fromWhere;
10
treesToRemove.forEach( function ( element, index ) {
11
	oneTree=treesToRemove[ index ];
12
	fromWhere=treesInPath.indexOf(oneTree);
13
	treesInPath.splice(fromWhere,1);
14
	treesPool.push(oneTree);
15
	oneTree.visible=false;
16
	console.log("remove tree");
17
});

Conclusión

Crear un juego en 3D es un proceso complicado si no está usando una herramienta visual como Unity. Puede parecer intimidante o abrumador, pero déjame asegurarte que una vez que lo domines, te sentirás mucho más poderoso y creativo. Me gustaría que exploraras aún más utilizando los diversos marcos físicos o sistemas de partículas o los ejemplos oficiales.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Game Development tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.