From 70be7e0151d0ba3e33aded26530e1e03c82c83e4 Mon Sep 17 00:00:00 2001 From: BOTLester <58360400+BOTLester@users.noreply.github.com> Date: Mon, 11 May 2020 01:16:01 +0200 Subject: [PATCH] PerlinNoise map generator --- Game1/Game1.csproj | 7 + Game1/Sources/Crops/Farm.cs | 16 +- Game1/Sources/Crops/PerlinNoise.cs | 333 +++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+), 1 deletion(-) create mode 100644 Game1/Sources/Crops/PerlinNoise.cs diff --git a/Game1/Game1.csproj b/Game1/Game1.csproj index f2f8ba8..109cb08 100644 --- a/Game1/Game1.csproj +++ b/Game1/Game1.csproj @@ -87,6 +87,7 @@ + @@ -159,6 +160,9 @@ + + 0.2.0 + 2.3.1 @@ -183,6 +187,9 @@ 1.7.0 + + 4.7.0 + 4.5.4 diff --git a/Game1/Sources/Crops/Farm.cs b/Game1/Sources/Crops/Farm.cs index a54f738..9fbc3f1 100644 --- a/Game1/Sources/Crops/Farm.cs +++ b/Game1/Sources/Crops/Farm.cs @@ -13,11 +13,16 @@ class Farm private CropTypesHolder PresetCrops = new CropTypesHolder(); private int Update; private Astar astar = new Astar(); - + private PerlinNoise perlin = new PerlinNoise(); + private float[][] whiteNoise; + private float[][] perlinNoise; + //initializes the crops public void init(Vector2 Size, Vector2 housepos) { + whiteNoise = PerlinNoise.GenerateWhiteNoise(100, 100); + perlinNoise = PerlinNoise.GeneratePerlinNoise(whiteNoise, 1); PresetCrops.init(); r = new Random(); crops = new Crops[100, 100]; @@ -26,6 +31,8 @@ class Farm { for (int j = 0; j < 99; j++) { + int x = 0; + /* int x = r.Next(0, 3); if (x == 0) { @@ -35,6 +42,13 @@ class Farm { x = r.Next(1, 3); } + */ + if (perlinNoise[i][j] > 0 && perlinNoise[i][j] < 0.2f) + x = 0; + else if (perlinNoise[i][j] >= 0.2f && perlinNoise[i][j] < 0.7f) + x = 1; + else if (perlinNoise[i][j] >= 0.7f) + x = 2; crops[i, j] = new Crops(); crops[i, j].setStatus(x); crops[i, j].setOriginalStatus(); diff --git a/Game1/Sources/Crops/PerlinNoise.cs b/Game1/Sources/Crops/PerlinNoise.cs new file mode 100644 index 0000000..723dfbf --- /dev/null +++ b/Game1/Sources/Crops/PerlinNoise.cs @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using System.Drawing.Imaging; + +class PerlinNoise +{ + #region Feilds + static Random random = new Random(); + #endregion + + #region Reusable Functions + + public static float[][] GenerateWhiteNoise(int width, int height) + { + float[][] noise = GetEmptyArray(width, height); + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + noise[i][j] = (float)random.NextDouble() % 1; + } + } + + return noise; + } + + public static float Interpolate(float x0, float x1, float alpha) + { + return x0 * (1 - alpha) + alpha * x1; + } + + public static Color Interpolate(Color col0, Color col1, float alpha) + { + float beta = 1 - alpha; + return Color.FromArgb( + 255, + (int)(col0.R * alpha + col1.R * beta), + (int)(col0.G * alpha + col1.G * beta), + (int)(col0.B * alpha + col1.B * beta)); + } + + public static Color GetColor(Color gradientStart, Color gradientEnd, float t) + { + float u = 1 - t; + + Color color = Color.FromArgb( + 255, + (int)(gradientStart.R * u + gradientEnd.R * t), + (int)(gradientStart.G * u + gradientEnd.G * t), + (int)(gradientStart.B * u + gradientEnd.B * t)); + + return color; + } + + public static Color[][] MapGradient(Color gradientStart, Color gradientEnd, float[][] perlinNoise) + { + int width = perlinNoise.Length; + int height = perlinNoise[0].Length; + + Color[][] image = GetEmptyArray(width, height); //an array of colours + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + image[i][j] = GetColor(gradientStart, gradientEnd, perlinNoise[i][j]); + } + } + + return image; + } + + public static T[][] GetEmptyArray(int width, int height) + { + T[][] image = new T[width][]; + + for (int i = 0; i < width; i++) + { + image[i] = new T[height]; + } + + return image; + } + + public static float[][] GenerateSmoothNoise(float[][] baseNoise, int octave) + { + int width = baseNoise.Length; + int height = baseNoise[0].Length; + + float[][] smoothNoise = GetEmptyArray(width, height); + + 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; + + for (int j = 0; j < height; j++) + { + //calculate the vertical sampling indices + int sample_j0 = (j / samplePeriod) * samplePeriod; + int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around + float vertical_blend = (j - sample_j0) * sampleFrequency; + + //blend the top two corners + float top = Interpolate(baseNoise[sample_i0][sample_j0], + baseNoise[sample_i1][sample_j0], horizontal_blend); + + //blend the bottom two corners + float bottom = Interpolate(baseNoise[sample_i0][sample_j1], + baseNoise[sample_i1][sample_j1], horizontal_blend); + + //final blend + smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend); + } + } + + return smoothNoise; + } + + public static float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount) + { + int width = baseNoise.Length; + int height = baseNoise[0].Length; + + float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing + + float persistance = 0.7f; + + //generate smooth noise + for (int i = 0; i < octaveCount; i++) + { + smoothNoise[i] = GenerateSmoothNoise(baseNoise, i); + } + + float[][] perlinNoise = GetEmptyArray(width, height); //an array of floats initialised to 0 + + 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++) + { + for (int j = 0; j < height; j++) + { + perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude; + } + } + } + + //normalisation + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + perlinNoise[i][j] /= totalAmplitude; + } + } + + return perlinNoise; + } + + public static float[][] GeneratePerlinNoise(int width, int height, int octaveCount) + { + float[][] baseNoise = GenerateWhiteNoise(width, height); + + return GeneratePerlinNoise(baseNoise, octaveCount); + } + + public static Color[][] MapToGrey(float[][] greyValues) + { + int width = greyValues.Length; + int height = greyValues[0].Length; + + Color[][] image = GetEmptyArray(width, height); + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + int grey = (int)(255 * greyValues[i][j]); + Color color = Color.FromArgb(255, grey, grey, grey); + + image[i][j] = color; + } + } + + return image; + } + + public static void SaveImage(Color[][] image, string fileName) + { + int width = image.Length; + int height = image[0].Length; + + Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + bitmap.SetPixel(i, j, image[i][j]); + } + } + + bitmap.Save(fileName); + } + + public static Color[][] LoadImage(string fileName) + { + Bitmap bitmap = new Bitmap(fileName); + + int width = bitmap.Width; + int height = bitmap.Height; + + Color[][] image = GetEmptyArray(width, height); + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + image[i][j] = bitmap.GetPixel(i, j); + } + } + + return image; + } + + public static Color[][] BlendImages(Color[][] image1, Color[][] image2, float[][] perlinNoise) + { + int width = image1.Length; + int height = image1[0].Length; + + Color[][] image = GetEmptyArray(width, height); //an array of colours for the new image + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + image[i][j] = Interpolate(image1[i][j], image2[i][j], perlinNoise[i][j]); + } + } + + return image; + } + + public static void DemoGradientMap() + { + int width = 256; + int height = 256; + int octaveCount = 8; + + Color gradientStart = Color.FromArgb(255, 0, 0); + Color gradientEnd = Color.FromArgb(255, 0, 255); + + float[][] perlinNoise = GeneratePerlinNoise(width, height, octaveCount); + Color[][] perlinImage = MapGradient(gradientStart, gradientEnd, perlinNoise); + SaveImage(perlinImage, "perlin_noise.png"); + } + + public static float[][] AdjustLevels(float[][] image, float low, float high) + { + int width = image.Length; + int height = image[0].Length; + + float[][] newImage = GetEmptyArray(width, height); + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + float col = image[i][j]; + + if (col <= low) + { + newImage[i][j] = 0; + } + else if (col >= high) + { + newImage[i][j] = 1; + } + else + { + newImage[i][j] = (col - low) / (high - low); + } + } + } + + return newImage; + } + + private static Color[][][] AnimateTransition(Color[][] image1, Color[][] image2, int frameCount) + { + Color[][][] animation = new Color[frameCount][][]; + + float low = 0; + float increment = 1.0f / frameCount; + float high = increment; + + float[][] perlinNoise = AdjustLevels( + GeneratePerlinNoise(image1.Length, image1[0].Length, 9), + 0.2f, 0.8f); + + for (int i = 0; i < frameCount; i++) + { + AdjustLevels(perlinNoise, low, high); + float[][] blendMask = AdjustLevels(perlinNoise, low, high); + animation[i] = BlendImages(image1, image2, blendMask); + //SaveImage(animation[i], "blend_animation" + i + ".png"); + SaveImage(MapToGrey(blendMask), "blend_mask" + i + ".png"); + low = high; + high += increment; + } + + return animation; + } + + #endregion +} \ No newline at end of file