top of page

[XNA/MG] Voxel Engine - 4 - Adding Noise


So.. our terrain looks good. But it's flat, and we want it to look more like a real terrain.


But MonoGame doesn't have a noise Library. Thankfully, Auburns made one in C# that we can use. It's called FastNoise, and you can get it here ("FastNoise.cs"). Add it to your project, or create a new class and paste the script in it.


Now that you have a noise system in your project, you can open the "Terrain" class :

We will need two new variables.

int blockSize = 16;

This is the size for one block image. It gives the size of the rectangle and we use it like before to know where to put a block next to the other in pixels.

int worldOffset = 10;

This will be used to bring down or up the world, avoiding hidden blocks that are too high to be seen with the noise.


Now go to the "Draw" method :

This time, the loops are X = 0 until X < 50 and Y = 0 until Y < 30.


Remove everything inside the loop, we will change almost everything

Let's start by adding our noise system. The noise will be calculated for each position in the loops.

FastNoise noise = new FastNoise();

We implement a new noise System to use. This will be where we calculate values.


float noiseValue = (float)Math.Floor(noise.GetPerlin(x * 5, 0) * 100);

We store the value of the noise in a float. It will return a value between 0 and 1. That's why we use "100" to make it bigger and return a value in our pixel world. The "Math.Floor" part will make sure the value is rounded to the floor value. (Ex : 10,678 will be = 10). Finally, we want to get the noise at the x position of the loop, "the first position", and multiplied by 5 to avoid having values that are too close to each other. So we don't have to use more blocks to give a good shape. It is used as the Frequency. You can say that "100" is the Amplitude.


noiseValue = (float)-Math.Floor(noiseValue / blockSize) * blockSize;

The result will be returned as a negative value, that's why we use "-". We divide the value by the block size, and the floor value of what is returned is multiplied by the block size. This will give the position of the noise value in a 16x16 grid. (Or a blockSize x blockSize grid). Thats also what we will use to get the mouse position in the world grid to place and remove blocks.


Now that we have our noise value, we can draw our terrain :

Just like before, we will draw between "Begin" and "End". And again, begin will have the world matrix.


We need 3 values. For each loop, we will use the actual X and Y positions of the block in the grid. And we also need the Y position of the block with the world offset added to it.

int actualX = x * blockSize;

Just like before, we multiply the actual X or Y by the block size to put them next to each other. (Ex : Block number 3 will be placed at "3 * 16", or "3 * the size of a block")

int actualOffsetY = (y * blockSize) - (worldOffset * blockSize);

This time, to have the Y value with the offset, we need the Y position of the block and subtract the offset, still multiplied by the block size. It will bring the world down. We have to subtract to keep the coordinates system which is 0,0 = Top Left, like before.


Now. Let's check if in this loop, the Y position, with the offset is the same as the noise value. If it is, we can draw a grass block at the actual X and Y position like before :


If you test your project, this is what you will see :


And this is without the offset at the Y position :

The blocks before 0 aren't rendered, but the noise requires them to go above. That's where we need the offset. With the offset, we can have air blocks replaceable by real blocks above the grass instead of null blocks and errors.


There is one last thing to do. Now we check if we are under the grass (Y with offset > than noise value, because we draw from up to down). If we are, we add a Stone block :


Test your project once again and this is what you should see. The final noise system added :


314 vues0 commentaire

Posts récents

Voir tout
bottom of page