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.