java - Diamonds and Squares Algorithm not working -
i working on making fractal terrain, no matter try, comes out looking random. have been following diamonds , squares algorithm explained here. can fix problem?
this terrain class:
package game; import java.util.random; public class terrain { panel panel; public terrain(panel panel) { this.panel = panel; generateterrain(); } private void generateterrain() { random rand = new random(); int seed = rand.nextint(panel.colors.length); int sidelength = panel.mapsize - 1; int halfsidelength; int average; panel.map[0][0] = seed; panel.map[panel.mapsize - 1][0] = seed; panel.map[0][panel.mapsize - 1] = seed; panel.map[panel.mapsize - 1][panel.mapsize - 1] = seed; while (sidelength > 0) { halfsidelength = sidelength / 2; (int x = 0; x < panel.mapsize - 1; x += sidelength) { (int y = 0; y < panel.mapsize - 1; y += sidelength) { average = panel.map[x][y] + panel.map[x + sidelength][y] + panel.map[x][y + sidelength] + panel.map[x + sidelength][y + sidelength]; average /= 4; average += rand.nextint(8); panel.map[x + halfsidelength][y + halfsidelength] = average; } } (int x = 0; x < panel.mapsize - 1; x += sidelength) { (int y = 0; y < panel.mapsize - 1; y += sidelength) { average = panel.map[x][y] + panel.map[x + halfsidelength][y] + panel.map[x][y + sidelength] + panel.map[x + halfsidelength][y + halfsidelength]; average /= 4; panel.map[x][y] = average; if (x == 0) { panel.map[panel.mapsize - 1][y] = average; } if (y == 0) { panel.map[x][panel.mapsize - 1] = average; } } } sidelength /= 2; } } }
and panel class:
package game; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class panel extends jpanel implements actionlistener { terrain currentterrain; boolean uppressed = false; boolean rightpressed = false; boolean downpressed = false; boolean leftpressed = false; int tilesize = 1; int mapsize = 1025; int deltax = 0; int deltay = 0; int x = 0; int y = 0; int map[][] = new int[mapsize][mapsize]; color[] colors = { new color(0, 0, 180), new color(0, 0, 255), new color(0, 150, 255), new color(255, 255, 180), new color(220, 220, 120), new color(200, 200, 60), new color(0, 200, 0), new color(0, 180, 0), new color(0, 160, 0), new color(0, 140, 0), new color(0, 120, 0), new color(0, 100, 0), new color(0, 80, 0), new color(0, 60, 0), new color(0, 40, 0), new color(40, 40, 40), new color(60, 60, 60), new color(80, 80, 80), new color(100, 100, 100), new color(120, 120, 120), new color(255, 255, 255) }; public panel(main main) { setpreferredsize(main.getsize()); setfocusable(true); setbackground(color.white); add(new keybindings(this)); currentterrain = new terrain(this); new timer(1000 / 120, this).start(); } private void tick() { if (uppressed) { deltay += 10; } else if (downpressed) { deltay -= 10; } if (rightpressed) { deltax -= 10; } else if (leftpressed) { deltax += 10; } repaint(); } @override public void actionperformed(actionevent e) { tick(); } @override public void paintcomponent(graphics g) { super.paintcomponent(g); x = 0; y = 0; (int[] rowdata : map) { (int celldata : rowdata) { int v = celldata; if(v < 0) { v = 0; } else if(v > colors.length - 1) { v = colors.length - 1; } g.setcolor(colors[v]); g.fillrect(x + deltax, y + deltay, tilesize, tilesize); x += tilesize; if(x == mapsize * tilesize) { x = 0; y += tilesize; } } } } }
you've got diamond stage of algorithm wrong. centres of diamonds midpoints of square's sides. best treated in 2 separate loops: 1 vertical midpoinst , second horizontal midpoints. @ edge of map, tips of diamnds reach out of map. can solve "folding" them map, example @ left edge, right point considered twice.
so code should be:
function generateterrain() { int seed = rand.nextint(colors.length); int sidelength = mapsize - 1; int halfsidelength; int average; int offset = 8; map[0][0] = seed; map[mapsize - 1][0] = seed; map[0][mapsize - 1] = seed; map[mapsize - 1][mapsize - 1] = seed; while (sidelength > 0) { halfsidelength /= 2; (int x = 0; x < mapsize - 1; x += sidelength) { (int y = 0; y < mapsize - 1; y += sidelength) { average = map[x][y] + map[x + sidelength][y] + map[x][y + sidelength] + map[x + sidelength][y + sidelength]; average /= 4; average += rand.nextint(offset); map[x + halfsidelength][y + halfsidelength] = average; } } (int x = 0; x < mapsize - 1; x += sidelength) { (int y = 0; y < mapsize; y += sidelength) { int ytop = y - halfsidelength; int ybottom = y + halfsidelength; if (ytop < 0) ytop = y + halfsidelength; if (ybottom > mapsize - 1) ybottom = y - halfsidelength; average = map[x][y] + map[x + sidelength][y] + map[x + halfsidelength][ytop] + map[x + halfsidelength][ybottom]; average = /= 4; map[x + halfsidelength][y] = average; } } (int x = 0; x < mapsize; x += sidelength) { (int y = 0; y < mapsize - 1; y += sidelength) { int xleft = x - halfsidelength; int xright = x + halfsidelength; if (xleft < 0) xleft = x + halfsidelength; if (xright > mapsize - 1) xright = x - halfsidelength; average = map[x][y] + map[x][y + sidelength] + map[xright][y + halfsidelength] + map[xright][y + halfsidelength]; average /= 4; map[x][y + halfsidelength] = average; } } sidelength /= 2; } }
(note: i've worked code, converted javascript , back, there java blunders still in it. think idea of 2 loops clear.)
this give noisy maps. usually, random offset (8 in code) reduced constant factor every time halve side length. smoothness of map can controlled parameter , interesting play it. in case, parameter 1.0. factor realistic maps around 0.65.
there's problem of method: use narrow integers throughout. use "narrow" here mean, granularity of integers, namely 1, equal colour change in map. doesn't give lot of range random variation within 1 colour. might idea either use floating-point numbers or integers of wider range map generation , map these values colours.
for example, use floating-point numbers between 0.0 , 1.0: map values below 0.1 dark green, below 0.2 light green , on until white values above 0.9. give smoother banded appearence in cloud picture below section of article linked.
another thing start random value @ corners , clamp values range of colours when printing map. random offset add positive, if start "high" colour, white picture. in fact, won't colour below starting value. start middle colour , allow both negative , positive random offsets circumvent this. or normalize map based on lowest , highest values after generating it.
Comments
Post a Comment