程序树生成器中的问题。 C# 统一

问题描述 投票:0回答:1

我目前正在开发一个程序地形生成器,在我的场景中程序生成树木时遇到了一个问题。 Unity 给了我一个错误,但我真的不知道如何解决这个问题。

unity error

这是我的世界生成器和树生成器的代码。

世界生成器

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, this.terrainWidthInChunks * terrainWidthInVertices, 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 acquiring the remainder of the division operation above
        // this translates the 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;
    }
}

树生成器:

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, 0, 0, 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 retrieves 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 obviously 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);
                    }
                }
            }
        }
    }
}
c# unity-game-engine tree procedural-generation procedural
1个回答
0
投票

在GenerateWorld()方法中,我看到您正在使用treeGenerator.GenerateTrees方法,但我没有看到treeGenerator对象的任何初始化。这是您收到错误的地方吗?那么你需要在使用它之前初始化类对象。

我认为您还需要初始化 RiverGenerator 对象。

© www.soinside.com 2019 - 2024. All rights reserved.