我正在尝试使用 Perlin 噪声作为统一生成森林/2D 预制件簇的模式,用于我的程序生成游戏。所以我的计划是生成 Perlin 噪声,然后使用 Perlin 噪声的暗色调生成看起来像森林的游戏对象簇。 生成的噪声具有 offsetX 和 offsetY 值,该值是 0 到 999999 之间的随机数,用于随机抵消帧内生成的噪声。噪声显示在四边形中,但完成后我将仅使用游戏对象,而不使用它们下面的噪声。现在我只有可见的噪声,这样我就可以看到生成点和噪声之间的相关性。 所以问题是,现在,它在技术上是有效的,但是游戏对象是根据偏移X 0和偏移Y 0处的帧中的噪声生成的,但是噪声每次都是随机的,但不是生成的游戏对象,所以对于某些原因是,RandomObjectSpawner 脚本不使用 offsetX 和 offsetY 值来计算,告诉它它是哪个噪声“帧”,(例如)在 offsetX 28904、offsetY 98201 噪声种子处,它仍然会生成以下模式中的点:偏移 0 噪声位置。 将提供示例屏幕截图。
这是 的图像,位于 offsetX 0 和 offsetY 0 处
这是 的时候: 正如您在图 2 中看到的,小占位符测试植物的生成方式与第一张图片几乎相同。所以我需要它们始终以随机生成的 offsetX 和 offsetY 值的模式生成。
以下是我生成柏林噪声的代码: `公共类 PerlinNoise :MonoBehaviour { // 纹理尺寸 公共整数宽度= 256; 公共 int 高度 = 256;
// Scale and offset parameters for controlling Perlin noise
public float scale = 20f;
public float offsetX = 0f;
public float offsetY = 0f;
void Start()
{
// Randomize the offsets to create different noise patterns
offsetX = Random.Range(0f, 999999f);
offsetY = Random.Range(0f, 999999f);
}
void Update()
{
// Get the renderer component of the attached GameObject
Renderer renderer = GetComponent<Renderer>();
// Apply the generated texture to the object's material
renderer.material.mainTexture = GenerateTexture();
}
// Make the GenerateTexture method public
public Texture2D GenerateTexture()
{
// Create a new 2D texture with specified dimensions
Texture2D texture = new Texture2D(width, height);
// Generate a Perlin noise map for the texture
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
// Calculate the color for the current pixel using Perlin noise
Color color = CalculateColor(x, y);
// Set the pixel's color in the texture
texture.SetPixel(x, y, color);
}
}
// Apply changes to the texture
texture.Apply();
return texture;
}
Color CalculateColor(int x, int y)
{
// Calculate the normalized coordinates within the texture
float xCoord = (float)x / width * scale + offsetX;
float yCoord = (float)y / height * scale + offsetY;
// Generate a Perlin noise value at the given coordinates
float sample = Mathf.PerlinNoise(xCoord, yCoord);
// Create a grayscale color using the Perlin noise value
return new Color(sample, sample, sample);
}
}`
这是我在游戏对象中生成的代码: `公共类 RandomObjectSpawner : MonoBehaviour { // 在暗色调上实例化的预制件 公共游戏对象预制实例化;
// Reference to the PerlinNoise script
public PerlinNoise perlinNoiseScript;
// Threshold to determine dark tones
public float threshold = 0.4f;
// Number of objects to spawn
public int numberOfObjects = 10;
void Start() {
// Ensure that the PerlinNoise script is assigned in the Inspector
if (perlinNoiseScript == null) {
Debug.LogError("PerlinNoise script is not assigned.");
return;
}
// Get the offsetX and offsetY values from the PerlinNoise script
float offsetX = perlinNoiseScript.offsetX;
float offsetY = perlinNoiseScript.offsetY;
// Generate the Perlin noise texture
Texture2D noiseTexture = perlinNoiseScript.GenerateTexture();
// Calculate the width and height of the generated texture
int width = noiseTexture.width;
int height = noiseTexture.height;
// Create a list to store available spawn positions
List<Vector2Int> availableSpawnPositions = new List<Vector2Int>();
// Loop through the pixels of the Perlin noise texture, starting from offsetX and offsetY
for (int x = (int)perlinNoiseScript.offsetX; x < width; x++) {
for (int y = (int)perlinNoiseScript.offsetY; y < height; y++) {
// Get the color at the current pixel
Color color = noiseTexture.GetPixel(x, y);
// Check if the grayscale value is below the threshold
if (color.grayscale <= threshold) {
// Add the position to the list of available spawn positions
availableSpawnPositions.Add(new Vector2Int(x, y));
}
}
}
// Shuffle the list of available spawn positions for randomness
ShuffleList(availableSpawnPositions);
// Spawn the specified number of objects randomly from the shuffled list
int spawnedObjectCount = 0;
foreach (Vector2Int spawnPosition in availableSpawnPositions) {
if (spawnedObjectCount >= numberOfObjects)
break;
// Calculate the world position for the object based on texture coordinates
float worldX = (spawnPosition.x - (int)perlinNoiseScript.offsetX) * perlinNoiseScript.transform.localScale.x / width + perlinNoiseScript.transform.position.x - (perlinNoiseScript.transform.localScale.x / 2.0f);
float worldY = (spawnPosition.y - (int)perlinNoiseScript.offsetY) * perlinNoiseScript.transform.localScale.y / height + perlinNoiseScript.transform.position.y - (perlinNoiseScript.transform.localScale.y / 2.0f);
float worldZ = perlinNoiseScript.transform.position.z;
// Spawn the object at the calculated position
Instantiate(prefabToInstantiate, new Vector3(worldX, worldY, worldZ), Quaternion.identity);
spawnedObjectCount++;
}
}
// Function to shuffle a list
void ShuffleList<T>(List<T> list) {
int n = list.Count;
while (n > 1) {
n--;
int k = Random.Range(0, n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}`
提前致谢。 :)
由于您在 Start() 中运行随机发生器,
void Start()
{
// Randomize the offsets to create different noise patterns
offsetX = Random.Range(0f, 999999f);
offsetY = Random.Range(0f, 999999f);
}
同时在Start()中设置柏林噪声纹理
void Start() {
if (perlinNoiseScript == null) {
Debug.LogError("PerlinNoise script is not assigned.");
return;
}
//Race condition here
float offsetX = perlinNoiseScript.offsetX;
float offsetY = perlinNoiseScript.offsetY;
您最终会尝试同时获取 perlinNoiseScript.offsetX,而噪声脚本仍在随机化数字。 Unity 通过让类返回在运行任何 Awake() 方法之后但在调用任何 Start() 方法之前存在的值来防止在这些函数期间发生竞争条件。因此,您得到的是输入检查器的数字,而不是 Start() 期间设置的数字。
要解决此问题,只需将偏移随机化器代码移至 Awake() 函数中,该函数在帧中启动任何 Start() 函数之前运行。
void Awake()
{
// Randomize the offsets to create different noise patterns
offsetX = Random.Range(0f, 999999f);
offsetY = Random.Range(0f, 999999f);
}