Skip to content

Instantly share code, notes, and snippets.

@FlorianCassayre
Created August 24, 2016 16:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FlorianCassayre/009f056ed1f6a7849c01d01e90ca5035 to your computer and use it in GitHub Desktop.
Save FlorianCassayre/009f056ed1f6a7849c01d01e90ca5035 to your computer and use it in GitHub Desktop.
Random fractal generator. Customizable & scalable.
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
/**
* Random fractal generator that looks like terrain.
* Since this is just an example, it doesn't keep track of the 'window' location.
* Inspired by Minecraft.
* @author Florian Cassayre
*/
public class RandomFractalGenerator
{
/**
* One good seed, one good p-RNG
*/
private static Random random = new Random(42L);
/**
* Test method
* @param args no params
*/
public static void main(String[] args)
{
System.out.println("Generating...");
long t1 = System.nanoTime();
int[][] ints = generate();
long t2 = System.nanoTime();
System.out.println("Done in " + (t2 - t1) + "ns.");
System.out.println("Saving...");
Utils.save(ints);
long t3 = System.nanoTime();
System.out.println("Done in " + (t3 - t2) + "ns.");
}
/**
* Generates a custom fractal
* @return the map
*/
public static int[][] generate()
{
// Dirty example, can be much more cleaner
int[][] ints = getFirstIslands(16, 16, 3);
ints = zoom(zoom(zoom(ints)));
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
if(ints[x][y] == 0 && random.nextInt(10) == 0)
ints[x][y] = 1;
ints = zoom(zoom(zoom(ints)));
for(int i = 0; i < 4; i++)
ints = smooth(ints);
// In case you're wondering, this code just creates a junction between two terrains, here it's the beach
int[][] copy = Utils.copy(ints);
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
{
int top = y > 1 ? ints[x][y - 1] : -1,
bottom = y < ints[0].length - 1 ? ints[x][y + 1] : -1,
left = x > 1 ? ints[x - 1][y] : -1,
right = x < ints.length - 1 ? ints[x + 1][y] : -1;
if((top == 0 || bottom == 0 || left == 0 || right == 0) && (top == 1 || bottom == 1 || left == 1 || right == 1))
copy[x][y] = 3;
}
ints = copy;
ints = smooth(ints);
ints = zoom(ints);
for(int i = 0; i < 4; i++)
ints = smooth(ints);
int[][] biomes = getFirstIslands(31, 31, 2);
biomes = smooth(zoom(biomes));
biomes = zoom(biomes);
biomes = zoom(biomes);
for(int i = 0; i < 2; i++)
{
biomes = zoom(biomes);
biomes = smooth(biomes);
}
for(int i = 0; i < 2; i++)
biomes = zoom(biomes);
for(int i = 0; i < 10; i++)
biomes = smooth(biomes);
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
if(ints[x][y] == 1)
if(biomes[x][y] == 0)
ints[x][y] = 1;
else
ints[x][y] = 2;
return ints;
}
/**
* Generates first islands into a new map
* @param width the map width
* @param height the map height
* @param frequency the island frequency
* @return a new map
*/
public static int[][] getFirstIslands(int width, int height, int frequency)
{
int[][] ints = new int[width][height];
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
ints[x][y] = random.nextInt(frequency) == 0 ? 0 : 1;
return ints;
}
/**
* Magnifies the map, initial array size <code>n</code> becomes <code>2n-1</code>
* @param ints the map
* @return a copy of the map
*/
public static int[][] zoom(int[][] ints)
{
int[][] copy = new int[ints.length * 2 - 1][ints[0].length * 2 - 1];
for(int x = 0; x < copy.length; x++)
for(int y = 0; y < copy[0].length; y++)
{
int value = 0;
if((x & 0xfe) == x && (y & 0xfe) == y)
{
value = ints[x >> 1][y >> 1];
}
else if((x & 0xfe) + 1 == x && x < copy.length - 1)
{
value = random.nextBoolean() ? ints[x >> 1][y >> 1] : ints[(x >> 1) + 1][y >> 1];
}
else if((y & 0xfe) + 1 == y && y < copy[0].length - 1)
{
value = random.nextBoolean() ? ints[x >> 1][y >> 1] : ints[x >> 1][(y >> 1) + 1];
}
else if(x > 1 && y > 1 && x < copy.length - 1 && y < copy[0].length - 1)
{
switch(random.nextInt(4))
{
case 0:
value = ints[x >> 1][y >> 1];
break;
case 1:
value = ints[(x >> 1) + 1][y >> 1];
break;
case 2:
value = ints[x >> 1][(y >> 1) + 1];
break;
case 3:
value = ints[(x >> 1) + 1][(y >> 1) + 1];
break;
}
}
copy[x][y] = value;
}
return copy;
}
/**
* Add more smoothness to the map
* @param ints the map
* @return a smoothed version of the map
*/
public static int[][] smooth(int[][] ints)
{
int[][] copy = Utils.copy(ints);
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
{
if(x > 0 && y > 0 && x < ints.length - 1 && y < ints.length - 1)
{
int top = ints[x][y - 1], bottom = ints[x][y + 1], left = ints[x - 1][y], right = ints[x + 1][y];
int value = ints[x][y];
if(top == bottom && left == right)
{
value = random.nextBoolean() ? top : left;
}
else if(top == bottom)
{
value = top;
}
else if(left == right)
{
value = left;
}
copy[x][y] = value;
}
}
return copy;
}
}
/**
* Useful methods than does not affect generation
*/
final class Utils
{
private Utils() {}
/**
* Creates a copy of the map
* @param ints the map
* @return a copy
*/
public static int[][] copy(int[][] ints)
{
int[][] copy = new int[ints.length][ints[0].length];
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
copy[x][y] = ints[x][y];
return copy;
}
/**
* Prints the map in some kind of human-readable format
* @param ints the map
*/
public static void print(int[][] ints)
{
for(int x = 0; x < ints.length; x++)
{
for(int y = 0; y < ints[0].length; y++)
{
System.out.print(ints[x][y]);
}
System.out.println();
}
System.out.println();
}
/**
* Saves the map into an image file.
* @param ints
*/
public static void save(int[][] ints)
{
BufferedImage off_Image = new BufferedImage(ints.length, ints[0].length, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = off_Image.createGraphics();
Color[] colors = {Color.CYAN, Color.GREEN, new Color(38, 182, 44), Color.YELLOW, new Color(40, 67, 250)}; // Static color array
for(int x = 0; x < ints.length; x++)
for(int y = 0; y < ints[0].length; y++)
{
g.setColor(colors[ints[x][y]]);
g.fillRect(x, y, 1, 1);
}
try
{
ImageIO.write(off_Image, "png", new File(""));
} catch(IOException e)
{
System.out.println("Exception while saving!");
e.printStackTrace();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment