- Home /
How do I make biomes with perlin noise
I wanna know how I can change my perlin noise values or something at certain points to make changes in the environment to make biomes, like minecraft with the planes and hills, I wanna be able to do something like that. Here's the code.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateInfiniteWorld : MonoBehaviour
{
public GameObject player;
public GameObject blockGameObject;
public int worldSizeX;
public int worldSizeZ;
public float offsetX;
public float offsetZ;
public float noiseHeight;
public float gridOffset;
private Vector3 startPosition;
private Hashtable blockContainer = new Hashtable();
void Start()
{
offsetX = UnityEngine.Random.Range(1f, 2086040f);
offsetZ = UnityEngine.Random.Range(1f, 2086040f);
float upTime = Time.realtimeSinceStartup;
for (int x = -worldSizeX - 15; x < worldSizeX + 15; x++)
{
for (int z = -worldSizeZ - 15; z < worldSizeZ + 15; z++)
{
Vector3 pos = new Vector3(x * 1 + startPosition.x, generateNoise(x + xPlayerLocation, z + zPlayerLocation, 8f) * noiseHeight, z * 1 + startPosition.z);
string bName = $"Block-{((int)pos.x).ToString()},0,{((int)pos.z).ToString()}";
GameObject block = Instantiate(blockGameObject, pos, Quaternion.identity) as GameObject;
block.transform.SetParent(this.transform);
block.name = bName;
BlockData bData = new BlockData(block, upTime);
blockContainer.Add(block, bData);
}
}
}
private void Update()
{
if (Mathf.Abs(xPlayerMove) >= 1 || Mathf.Abs(zPlayerMove) >= 1)
{
float upTime = Time.realtimeSinceStartup;
for (int x = -worldSizeX; x < worldSizeX * 1.733; x++)
{
for (int z = -worldSizeZ; z < worldSizeZ * 1.733; z++)
{
Vector3 pos = new Vector3(x * 1 + (xPlayerLocation - 10), generateNoise(x + xPlayerLocation, z + zPlayerLocation, 8f) * noiseHeight, z * 1 + (zPlayerLocation - 10));
string bName = $"Block-{((int)pos.x).ToString()},0,{((int)pos.z).ToString()}";
if (!blockContainer.ContainsKey(bName))
{
GameObject block = Instantiate(blockGameObject, pos, Quaternion.identity) as GameObject;
block.transform.SetParent(this.transform);
block.name = bName;
BlockData bData = new BlockData(block, upTime);
blockContainer.Add(block, bData);
}
else
((BlockData)blockContainer[bName]).upTime = upTime;
}
}
Hashtable newBlockContainer = new Hashtable();
foreach (BlockData bData in blockContainer.Values)
{
if (Math.Abs(bData.upTime - upTime) > 0.0)
Destroy(bData.blockObj);
else
newBlockContainer.Add(bData.blockObj.name, bData);
}
blockContainer = newBlockContainer;
startPosition = player.transform.position;
}
}
public int xPlayerMove
{
get
{
return (int)(player.transform.position.x - startPosition.x);
}
}
public int zPlayerMove
{
get
{
return (int)(player.transform.position.z - startPosition.z);
}
}
public int xPlayerLocation
{
get
{
return (int)Mathf.Floor(player.transform.position.x);
}
}
public int zPlayerLocation
{
get
{
return (int)Mathf.Floor(player.transform.position.z);
}
}
private float generateNoise(int x, int z, float detailScale)
{
float xNoise = (x + this.transform.position.x) / detailScale;
float zNoise = (z + this.transform.position.y) / detailScale;
return Mathf.PerlinNoise(xNoise + offsetX, zNoise + offsetZ);
}
}
class BlockData
{
public GameObject blockObj;
public float upTime;
public BlockData(GameObject blockObj, float upTime)
{
this.blockObj = blockObj;
this.upTime = upTime;
}
}
Answer by Llama_w_2Ls · Oct 25, 2021 at 11:01 AM
You could use a large noise map to generate the location of the biomes. This could be a large scaled perlin noise, or even Voronoi noise, which is used by minecraft for regions and rivers I believe.
If you were using simple perlin noise, generate a large noise map first, and if the values are between a certain range, use a smaller perlin noise of your choise for that region. For example, where noise is of high values, you can have mountainous/snowy biomes, with much more hilly biomes, whereas areas of low noise could be desert/grass biomes, with mostly smooth and low-lying land.
Only problem, I'm not smart and have no clue how to do that
Create a class called noise, with fields such as scale, amplitude, height etc. These control what the biome looks like. Create multiple instances of these with differing scales and heights etc. so that they look different. You could also assign different blocks to the noise classes to make them separate biomes.
Then, use one noise instance as the biome map. Make the scale enormous, and whenever the noise is within a range, choose one of the noise biomes to use in that area. This will make your map consist of multiple biomes. Here's some code:
[System.Serializable]
public class Noise
{
public float Scale;
public float Amplitude;
public float Height;
public float Sample2D(float x, float y)
{
float noiseValue = Mathf.PerlinNoise(x / Scale, y / Scale);
return noiseValue * Amplitude + Height;
}
}
Create multiple instances of Noise class in the editor and set their parameters
public class WorldGen : MonoBehaviour
{
public Noise BiomeNoise; // Main noise, make it have a large scale
public Noise GrassNoise;
public Noise MountainNoise;
void Start()
{
var blocks = YOUR_BLOCKS; // Get this per chunk maybe
foreach (var block in blocks)
{
float biome = BiomeNoise.Sample2D(block.pos.x, block.pos.y);
if (biome < GrassThreshold)
// Sample from Grass Noise
// GrassThreshold = 2f for example
else
// Sample from Mountain Noise
}
}
}
Your answer
Follow this Question
Related Questions
Procedural Generation in Unity 0 Answers
Adding rivers to procedural generated 2D map 1 Answer
Unexpected period length with Unity Mathematics pnoise method 0 Answers
Better perlin noise map generation. 0 Answers
Strange texture2d behaviour 0 Answers