- Home /
How do I generate believable terrain for a 2D game using cubes?
Ok, I have a fairly simple code that spawns a moving block. It spawns them in a range.
Instantiate (defaultground, Vector3 (transform.position.x, Random.Range(0,2.5), transform.position.z), transform.rotation);
What I want to do with this snippet code is to replace it with code that can set a "trend", ie. instead of randomly making blocks, making it go up and down in hills. How should I approach this?
Answer by Herman-Tulleken · Jul 21, 2011 at 10:14 AM
Check out this:
http://devmag.org.za/2009/04/25/perlin-noise/
Basically, you can generate Perlin noise, and use that to drive the vertical position of your cubes.
I am not sure what you want to do---is using Unity's terrain system an option? There are also plug-ins for generating procedural landscape.
Edit: Here is an version from the DevMag article translated to Unity to get you started. It is 1D only... read the article for an explanation.
Here is how it looks:
...Sorry, QATO's image thing does not want to work... here is the link:
http://www.devmag.org.za/examples/perlin_noise/terrain.png
public class TerrainSpawn : MonoBehaviour
{
public GameObject cubePrefab;
public int cubesToGenerate = 20;
float[] GetEmptyArray(int width)
{
return new float[width];
}
float[] GenerateWhiteNoise(int width)
{
float[] noise = GetEmptyArray(width);
for (int i = 0; i < width; i++)
{
noise[i] = (float)Random.value;
}
return noise;
}
float Interpolate(float x0, float x1, float alpha)
{
return x0 * (1 - alpha) + alpha * x1;
}
float[] GenerateSmoothNoise(float[] baseNoise, int octave)
{
int width = baseNoise.Length;
float[] smoothNoise = GetEmptyArray(width);
int samplePeriod = 1 << octave; // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;
for (int i = 0; i < width; i++)
{
//calculate the horizontal sampling indices
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
smoothNoise[i] = Interpolate(baseNoise[sample_i0],
baseNoise[sample_i1], horizontal_blend);
}
return smoothNoise;
}
float[] GeneratePerlinNoise(float[] baseNoise, int octaveCount)
{
int width = baseNoise.Length;
float[][] smoothNoise = new float[octaveCount][]; //an array of 2D arrays containing
float persistance = 0.5f;
//generate smooth noise
for (int i = 0; i < octaveCount; i++)
{
smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
}
float[] perlinNoise = GetEmptyArray(width);
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--)
{
amplitude *= persistance;
totalAmplitude += amplitude;
for (int i = 0; i < width; i++)
{
perlinNoise[i] += smoothNoise[octave][i] * amplitude;
}
}
//normalisation
for (int i = 0; i < width; i++)
{
perlinNoise[i] /= totalAmplitude;
}
return perlinNoise;
}
public void Start()
{
float[] perlinNoise = GeneratePerlinNoise(GenerateWhiteNoise(cubesToGenerate), 5);
for (int i = 0; i < cubesToGenerate; i++)
{
GameObject gObject = (GameObject) Instantiate(cubePrefab);
gObject.transform.position = new Vector3(i, 4*perlinNoise[i], 0);
}
}
}
O$$anonymous$$. So using Perlin noise should be fine; you only need to generate 1D Perlin noise though. Here is a better article for the 1D case:
I'm not quite sure on how to make perlin noise in Unity. I only really know how to program things that directly relate to Unity.
O$$anonymous$$, I did a quick version for you. Play with the constants for different effects.
What do I change to make different ranges? I usually code in JavaScript so...