问题描述
我目前正在研究程序化地形生成器,但在我的场景中程序化生成树木时遇到了一个问题。 Unity 给了我一个错误,但我真的不知道如何解决这个问题。
世界生成器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TerrainGenerator : MonoBehavIoUr
{
[Serializefield]
private int terrainWidthInChunks,terrainLengthInChunks;
[Serializefield]
private GameObject ChunkPrefab;
[Serializefield]
private float centreVertex,maxdistance;
[Serializefield]
private TreeGenerator treeGenerator;
[Serializefield]
private RiverGenerator riverGenerator;
// Start is called before the first frame update
void Start()
{
GenerateWorld ();
}
void GenerateWorld()
{
//gets the chunk dimensions from the chunk prefab
Vector3 chunkSize = ChunkPrefab.GetComponent<MeshRenderer>().bounds.size;
int terrainHeight = (int)chunkSize.z;
int terrainWidth = (int)chunkSize.x;
//Calculates the number of vertices of the chunk in each axis of the mesh
Vector3[] terrainMeshVertices = ChunkPrefab.GetComponent<MeshFilter>().sharedMesh.vertices;
int terrainHeightInVertices = (int)Mathf.Sqrt(terrainMeshVertices.Length);
int terrainWidthInVertices = terrainHeightInVertices;
float distanceBetweenVertices = (float)terrainHeight / (float)terrainHeightInVertices;
//builds an empty object to be filled with the terrain chunks that are generated on run-time
WorldData worldData = new WorldData(terrainHeightInVertices,terrainWidthInVertices,this.terrainLengthInChunks,this.terrainWidthInChunks);
//for each chunk we will want to instantiate a chunk in the correct position
for (int x = 0; x < terrainWidthInChunks; x++)
{
for (int z = 0; z < terrainLengthInChunks; z++)
{
// calculates the chunk position based on x and z indices
Vector3 chunkPosition = new Vector3(this.gameObject.transform.position.x + x * terrainWidth,this.gameObject.transform.position.y,this.gameObject.transform.position.z + z * terrainHeight);
//instantiates new chunk
GameObject Chunk = Instantiate(ChunkPrefab,chunkPosition,Quaternion.identity) as GameObject;
//generates the chunk texture and stores it in ChunkData
ChunkData chunkData = Chunk.GetComponent<TerrainchunkGenerator>().GenerateChunk(centreVertex,maxdistance);
worldData.AddChunkData(chunkData,z,x);
}
}
//generates trees for the world
treeGenerator.GenerateTrees(this.terrainLengthInChunks * terrainHeightInVertices,this.terrainWidthInChunks * terrainWidthInVertices,distanceBetweenVertices,worldData);
//generates rivers for the world
riverGenerator.GenerateRivers(this.terrainLengthInChunks * terrainHeightInVertices,worldData);
}
}
//class to store merged chunk data
public class WorldData
{
private int terrainHeightInVertices,terrainWidthInVertices;
public ChunkData[,] chunksData;
public WorldData(int terrainHeightInVertices,int terrainWidthInVertices,int terrainLengthInChunks,int terrainWidthInChunks)
{
//builds the chunkdata matrix based on terrain depth and width in verts and chunks
chunksData = new ChunkData[terrainHeightInVertices * terrainLengthInChunks,terrainWidthInVertices * terrainWidthInChunks];
this.terrainHeightInVertices = terrainHeightInVertices;
this.terrainWidthInVertices = terrainWidthInVertices;
}
public void AddChunkData(ChunkData chunkData,int chunkZIndex,int chunkXIndex)
{
//saves the chunk data in the correct coordinates
chunksData[chunkZIndex,chunkXIndex] = chunkData;
}
public ChunkCoordinate ConverttochunkCoordinate(int z,int x)
{
//the chunk index is calculates by dividing the index by yhr number of chunks in that axis
int chunkZIndex = (int)Mathf.Floor((float)z / (float)this.terrainHeightInVertices);
int chunkXIndex = (int)Mathf.Floor((float)x / (float)this.terrainWidthInVertices);
//the coord index is calculated by aquiring the remainder of the division operation above
//this translates te origin to the bottom left corner
int coordinateZIndex = this.terrainHeightInVertices - (z % this.terrainHeightInVertices) - 1;
int coordinateXIndex = this.terrainWidthInVertices - (x % this.terrainWidthInVertices) - 1;
ChunkCoordinate chunkCoordinate = new ChunkCoordinate(chunkZIndex,chunkXIndex,coordinateZIndex,coordinateXIndex);
return chunkCoordinate;
}
}
//class that represents a coordinate in the chunk coordinate System
public class ChunkCoordinate
{
public int chunkZIndex;
public int chunkXIndex;
public int coordinateZIndex;
public int coordinateXIndex;
public ChunkCoordinate(int chunkZIndex,int chunkXIndex,int coordinateZIndex,int coordinateXIndex)
{
this.chunkZIndex = chunkZIndex;
this.chunkXIndex = chunkXIndex;
this.coordinateZIndex = coordinateZIndex;
this.coordinateXIndex = coordinateXIndex;
}
}
*tree generator*
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TreeGenerator : MonoBehavIoUr
{
[Serializefield]
private NoisemapGenerator noisemapGenerator;
[Serializefield]
private Octave[] octaves;
[Serializefield]
private float terrainScale;
[Serializefield]
private float[] neighborRadius;
[Serializefield]
private GameObject[] treePrefab;
public void GenerateTrees(int height,int width,float distanceBetweenVertices,WorldData worldData)
{
//Generates a tree noise map using the perlin noise function from noise map generator
float[,] treeNoiseMap = this.noisemapGenerator.GeneratePerlinNoiseMap(height,width,this.terrainScale,this.octaves);
float chunkSizeX = width * distanceBetweenVertices;
float chunkSizeZ = height * distanceBetweenVertices;
for (int z = 0; z < height; z++)
{
for (int x = 0; x < width; x++)
{
//converts from the world coord system to the chunk coord system and retreieves the chunkdata
ChunkCoordinate chunkCoordinate = worldData.ConverttochunkCoordinate(z,x);
ChunkData chunkData = worldData.chunksData[chunkCoordinate.chunkZIndex,chunkCoordinate.chunkXIndex];
int chunkWidth = chunkData.heightMap.GetLength(1);
//calculates the mesh vertex index
Vector3[] meshVertices = chunkData.mesh.vertices;
int vertexIndex = chunkCoordinate.coordinateZIndex * chunkWidth + chunkCoordinate.coordinateXIndex;
//gets the terrain region of this coord
TerrainRegion terrainRegion = chunkData.chosenHeightTerrainRegion[chunkCoordinate.coordinateZIndex,chunkCoordinate.coordinateXIndex];
//gets the current biome of the coord
Biome biome = chunkData.chosenBiomes[chunkCoordinate.coordinateZIndex,chunkCoordinate.coordinateXIndex];
//check if the coord is "water" terrain. We obvIoUslt don't want trees to be placed within the water
if (terrainRegion.name != "water")
{
float treeValue = treeNoiseMap[z,x];
int terrainRegionIndex = terrainRegion.index;
//compares the current noise value to the neighbouring values
int neighborZBegin = (int)Mathf.Max(0,z - this.neighborRadius[biome.index]);
int neighborZEnd = (int)Mathf.Min(height-1,z + this.neighborRadius[biome.index]);
int neighborXBegin = (int)Mathf.Max(0,x - this.neighborRadius[biome.index]);
int neighborXEnd = (int)Mathf.Min(width - 1,x + this.neighborRadius[biome.index]);
float maxValue = 0f;
for (int neighborZ = neighborZBegin; neighborZ <= neighborZEnd; neighborZ++)
{
for (int neighborX = neighborXBegin; neighborX <= neighborXEnd; neighborX++)
{
float neighborValue = treeNoiseMap[neighborZ,neighborX];
//saves the max tree noise values in the radius
if (neighborValue >= maxValue)
{
maxValue = neighborValue;
}
}
}
//if the current trees nise value is the max of one then place a tree in that location
if (treeValue == maxValue)
{
Vector3 treePosition = new Vector3(x * distanceBetweenVertices,meshVertices[vertexIndex].y,z * distanceBetweenVertices);
GameObject tree = Instantiate(this.treePrefab[biome.index],treePosition,Quaternion.identity) as GameObject;
tree.transform.localScale = new Vector3(0.05f,0.05f,0.05f);
}
}
}
}
}
}
解决方法
在 GenerateWorld() 方法中,我看到您正在使用 treeGenerator.GenerateTrees 方法,但我没有看到 treeGenerator 对象的任何初始化。这是您收到错误的地方。那么在使用之前需要对类对象进行初始化。
我认为您还需要初始化 riverGenerator 对象。