Jump to content
  • Advertisement
Sign in to follow this  
Draika the Dragon

Cave generation algorithm is generating patterns when its supposed to be random

This topic is 718 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was testing out a cave generation algorithm i made for a 2d orthographic game (like terraria) using the Cellular Automata method. I decided to stress test the algorithm originally to see if there was enough caves being generated so I decided to generate 100 massive levels and save them all a .png file so i could spot any problems.

 

I'm seeing a pattern across all the images where all the deep caves are sort of "streaking" towards the bottom right direction. I'm not really sure why this is happening. I am not sure how to pinpoint the reason since i only notice the pattern in a large scale. Does anyone have any ideas as to why my caves look like this?

 

Here's a sample of 3 different levels i generated

 

fjgvpi.png

 

et5cag.pngj8chw5.png

 

 

i don't know if it's a problem with my code but just in case here is the algorithm

	public static int groundFloorY = 360;
// the layout of the level. true = is a block, false = empty space
	public boolean[][] groundChart = new boolean[128 * 32][14 * 32];
	
	public List<PositionBlock> getBlocks(String[] args) {
		return cellularAutomata(6.2f, 4); // the settings i used to generate the images
	}
	
// generates ground as a list of blocks and their positions
	public List<PositionBlock> cellularAutomata(float wallTriesModifier,int iterations) {
		List<PositionBlock> ground = new ArrayList<PositionBlock>();
		Random random = new Random();

		// randomly fill the map with blocks
		for (int x = 0; x < 128 * groundFloorY * wallTriesModifier; x++) {
			int maxX = 128 * 32 - 32;
			int randomX = random.nextInt(maxX);
			int randomY = random.nextInt(groundFloorY);
			groundChart[randomX][randomY] = true;
		}
		// "grow" the terrain to generate a complete level 
		for (int automaiterations = 0; automaiterations < iterations-1; automaiterations++) {
			for (int i = 0; i < groundChart.length; i++) {
				for (int j = 0; j < groundChart[i].length; j++) {
					boolean block = groundChart[i][j];
					int neighbourBlocks = 0;
					int neighbourSpaces = 0;
					
					// get neighbouring nodes around a node
					List<Point> neighbours = ExtraUtils.getNeighbours(groundChart.length - 1, groundChart[0].length - 1, i, j, 1, true);
					
					// count the neighbours that are blocks
					for (int k = 0; k < neighbours.size(); k++) {
						Point neighbourLocation = neighbours.get(k);
						boolean neighbour = groundChart[neighbourLocation.x][neighbourLocation.y];
						if (neighbour) {
							neighbourBlocks++;
						} else {
							neighbourSpaces++;
						}
					}

					if (block) {
						
					} else {
						
						// Turn a node into a block if there are >= 4 neighbouring nodes, that aren't empty, around it			
						if (neighbourBlocks >= 4) {
							groundChart[i][j] = true;
						}
					}
				}
			}
		}
		// Final polish iteration
		for (int i = 0; i < groundChart.length; i++) {
			for (int j = 0; j < groundChart[i].length; j++) {
				boolean block = groundChart[i][j];
				int neighbourBlocks = 0;
				int neighbourSpaces = 0;
				
				// get neighbouring nodes around a node
				List<Point> neighbours = ExtraUtils.getNeighbours(groundChart.length - 1, groundChart[0].length - 1, i, j, 1, false);
				for (int k = 0; k < neighbours.size(); k++) {
					Point neighbourLocation = neighbours.get(k);
					boolean neighbour = groundChart[neighbourLocation.x][neighbourLocation.y];
					if (neighbour) {
						neighbourBlocks++;
					} else {
						neighbourSpaces++;
					}
				}

				if (block) {
					// remove random floaty blocks
					if (neighbourBlocks <= 1) {
						groundChart[i][j] = false;
					}
				}
			}
		}
		// Compile blocks into list
		for (int i = 0; i < groundChart.length; i++) {
			for (int j = 0; j < groundChart[i].length; j++) {
				boolean block = groundChart[i][j];
				if (block) {
					ground.add(new PositionBlock([block instance], new Point(i, j)));
				}
			}
		}
		return ground;
	}
public class PositionBlock {
    public final Point position;
    public final Block block; // not really relevant here

    public PositionBlock(Block block, Point position) {
        this.block = block;
        this.position = position;
    }
   
}
Edited by draika

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!