I. Introduction▲
Cette série explique comment générer de manière procédurale des continents dans Unity.
Vous pouvez retrouver les autres épisodes de cette série dans le sommaire dédié.
II. Vidéo▲
Unity - Génération procédurale de terrain - Terrain infini
III. Résumé▲
Dans cet épisode, vous allez mettre en place un terrain sans fin.
Pour cela, vous allez générer et afficher seulement les morceaux de terrain visibles par le joueur.
III-A. Implémentation▲
Créez un nouveau script EndlessTerrain.cs. Le but de ce script est de gérer les morceaux de terrain devant être visibles par le joueur.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class EndlessTerrain : MonoBehaviour {
public const float maxViewDst = 450;
public Transform viewer;
public static Vector2 viewerPosition;
int chunkSize;
int chunksVisibleInViewDst;
Dictionary<Vector2, TerrainChunk> terrainChunkDictionary = new Dictionary<Vector2, TerrainChunk>();
List<TerrainChunk> terrainChunksVisibleLastUpdate = new List<TerrainChunk>();
void Start() {
chunkSize = MapGenerator.mapChunkSize - 1;
chunksVisibleInViewDst = Mathf.RoundToInt(maxViewDst / chunkSize);
}
void Update() {
viewerPosition = new Vector2 (viewer.position.x, viewer.position.z);
UpdateVisibleChunks ();
}
void UpdateVisibleChunks() {
for (int i = 0; i < terrainChunksVisibleLastUpdate.Count; i++) {
terrainChunksVisibleLastUpdate [i].SetVisible (false);
}
terrainChunksVisibleLastUpdate.Clear ();
int currentChunkCoordX = Mathf.RoundToInt (viewerPosition.x / chunkSize);
int currentChunkCoordY = Mathf.RoundToInt (viewerPosition.y / chunkSize);
for (int yOffset = -chunksVisibleInViewDst; yOffset <= chunksVisibleInViewDst; yOffset++) {
for (int xOffset = -chunksVisibleInViewDst; xOffset <= chunksVisibleInViewDst; xOffset++) {
Vector2 viewedChunkCoord = new Vector2 (currentChunkCoordX + xOffset, currentChunkCoordY + yOffset);
if (terrainChunkDictionary.ContainsKey (viewedChunkCoord)) {
terrainChunkDictionary [viewedChunkCoord].UpdateTerrainChunk ();
if (terrainChunkDictionary [viewedChunkCoord].IsVisible ()) {
terrainChunksVisibleLastUpdate.Add (terrainChunkDictionary [viewedChunkCoord]);
}
} else {
terrainChunkDictionary.Add (viewedChunkCoord, new TerrainChunk (viewedChunkCoord, chunkSize, transform));
}
}
}
}
public class TerrainChunk {
GameObject meshObject;
Vector2 position;
Bounds bounds;
public TerrainChunk(Vector2 coord, int size, Transform parent) {
position = coord * size;
bounds = new Bounds(position,Vector2.one * size);
Vector3 positionV3 = new Vector3(position.x,0,position.y);
meshObject = GameObject.CreatePrimitive(PrimitiveType.Plane);
meshObject.transform.position = positionV3;
meshObject.transform.localScale = Vector3.one * size /10f;
meshObject.transform.parent = parent;
SetVisible(false);
}
public void UpdateTerrainChunk() {
float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance (viewerPosition));
bool visible = viewerDstFromNearestEdge <= maxViewDst;
SetVisible (visible);
}
public void SetVisible(bool visible) {
meshObject.SetActive (visible);
}
public bool IsVisible() {
return meshObject.activeSelf;
}
}
}Un dictionnaire (Dictionary) est utilisé afin de permettre la réutilisation de morceaux qui ont déjà été instanciés et donc, de ne pas instancier plusieurs objets pour la même position. Afin d'utiliser aisément le dictionnaire, une nouvelle classe TerrainChunk a été créée permettant de gérer la visibilité d'un bloc et la réutilisation d'un bloc en mettant à jour ses informations.
Le calcul de distance pour savoir si le morceau doit être visible ou non repose sur la classe Bounds de Unity.
Finalement, afin de rendre invisibles les morceaux qui ont été affichés par le passé, un tableau terrainChunksVisibleLastUpdate permet de garder tous les morceaux affichés. Ainsi, au début de la fonction UpdateVisibleChunks(), il est possible de les cacher.
Pour activer le script, créez un nouveau cube et assignez-lui le script. Pour tester son bon fonctionnement, lancez le projet et déplacez le cube dans l'éditeur.
IV. Commenter▲
Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.



