5
\$\begingroup\$

Let me start with the basics. Here's what I have:

  • A height map built on a few different combinations of noise functions
  • Rivers that are generated after the height map and flow from pseudorandom points to water following an A* algorithm

What I'm trying to do:

  • Create a "zoomed in" portion of this map without generating the whole map

Why?

  • The map is very large, and storing all the points in the height map in its zoomed-out form already takes 100+ Mb.
  • I decided the best way to store maps is just store the seeds used to generate them, which takes a couple of kilobytes.
  • This allows me to generate identical maps every time
  • However, when it comes to rendering such a map, the size does matter, since a bigger map means a bigger array/map/list holding it and a bigger chunk of memory dedicated to it.
  • So instead of rendering the whole map at once, I want to be able to render small, manageable sections and stitch them together into a full map with a higher resolution.

I figure that I can just sample the noise function more frequently, and this will fill in points in between points to increase resolution. This works. The problem is when I get to edge cases.

In the full map, I make the edge believe that everything beyond it is a copy of the edge tile in question.

When I get to the smaller section of the map, I'm not quite sure how to deal with the edge case, especially when it comes to rivers:

Say a river in the large map starts outside of the smaller section, but flows through the smaller section. How do I make sure that river is created?

Or say a river starts in my small section but ends at an ocean that isn't located in that section - an ocean that isn't generated at all but theoretically exists as a result of the noise function at those coordinates. Now what do I do?

I have an idea of a possible solution, but I don't know how to execute it. I generate sets of river tiles in my world generation code, and I could just generate a full map at low resolution and copy the river tiles to the smaller map. However, this would leave gaps in the river, realistically in every other tile if I zoomed in to 2x scale. Is there some way I can fill in surrounding tiles to ensure that my river won't change scale?

If you would like code or pictures, please comment and I'll post them. I'm just not sure what I need to include that would actually be helpful and not just clutter.

Edit: I'm adding some pictures that might help explain the situation, everyone likes pictures right? The first one is an "unzoomed" map. The second one has twice the resolution of the first - the equivalent of zooming in on the map but still generating the whole thing. You can see that some of the rivers are now flowing in different directions (I made sure they start in the same place) because the terrain is now more detailed and they have found better paths. I'm not as concerned about that as I am about the questions in bold above. I don't need multiple maps at different resolutions, I just need one big map at high resolution.

Not Zoomed

Map Zoomed 2x

\$\endgroup\$
  • \$\begingroup\$ Can you make any guarantees about river generation, e.g. is a river always contained inside the bounding box formed by the source and destination location? \$\endgroup\$ – Exilyth Aug 31 '16 at 17:30
  • \$\begingroup\$ @sarahm I might be able to if I was to generate destination points. I'm just using distance to water as a heuristic, but that's a great idea. \$\endgroup\$ – Nathaniel D. Hoffman Sep 1 '16 at 6:16
1
\$\begingroup\$

Rivers need to be generated as a result of the procedural generation, not pathfinding.

If you're going to use the map that way (not generating the whole thing, while viewing zoomed in portions), you can't generate your rivers with pathfinding. Essentially, the rivers should be fractal. Just like your terrain, you can zoom in to rivers for additional detail, but the larger structures of the fractal remain static.

However, this can't simply be another layer of noise, it needs to be closely tied to your existing terrain. Without knowing more about how you're generating the terrain it's hard to give specifics. But, you can use elevation data, moisture levels and multiple other layers to determine if a river should exist.

You may be able to combine strategies to ensure your rivers always reach oceans or lakes. Use pathfinding for your high level map. Then, when generating high resolution maps, utilize the pathfinding data from the lower resolution maps. This is essentially fractal pathfinding. When pathfinding for higher resolution, all you need to do is pathfind between each of the points found in the higher resolution.

\$\endgroup\$
  • 2
    \$\begingroup\$ You may want to wait a day or two before accepting, it encourages additional answers. \$\endgroup\$ – MichaelHouse Aug 14 '16 at 4:30
  • \$\begingroup\$ ^^ Got it - I played around with the second part of your answer all day, but without the fractal generation, just using pathfinding, and found myself in a confusing mess of code, so my plan now is to rework the whole river generation to be procedural like you suggest. I'm using a Perlin noise generator to create the height map, with a ridged multi-fractal distort (which isn't entirely necessary). I then generate a heat map with another ridged multi-fractal (adjusted for longitude and elevation) and a moisture map the same way as the heat map. I combine all three maps together to create biomes. \$\endgroup\$ – Nathaniel D. Hoffman Aug 14 '16 at 4:39
  • \$\begingroup\$ I'm also using the github.com/flow/noise library to generate my noise. It's based off of Libnoise but for Java. \$\endgroup\$ – Nathaniel D. Hoffman Aug 14 '16 at 4:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.