Idraluna Archives

(Automated) Die-drop Hexmaps with Minecraft Biomes

A couple of weeks ago, Zak H. of Bommyknocker Press posted this really cool guide to using die drops to generate diverse Minecraft-esque biomes.

Being as a GIS nerd, I kept noticing that the basic steps are all fundamental geoprocessing operations, so (with Zak's blessing) I automated it in R (terra), hoping to host it on itch.io as a shiny app. Unfortunately, itch seems to freak out at at least one of the terra dependencies and troubleshooting web apps is above my pay grade. So for a functional but slightly disappointing alternative, I wired it up in the QGIS model builder.

If you want to try it, download it here and grab the biome .csv file here, save them to a QGIS project directory, and load the csv into your QGIS layer list and the model in the QGIS Model Designer window (accessed through the Processing menu in the top ribbon). Then hit the green arrow to run it, and plug in whatever parameters you want.

Implementation

Here's the model in its tangled glory:

The light green boxes represent inputs, which should be self-explanatory.

To visualize the output, right-click the hex layer and select Properties, navigate to the Symbology tab, select Categorized symbology, select the Biome field, and press Classify to assign each biome a random color. You can then double-click the swatches to set them manually if desired.

Notes

I really like how this method creates organic-looking blobby biomes and works off of Minecraft's evocative biome types. Also, despite all the effort I sunk into automating it, I think it's awesome that this method can be done by hand.

I think it would be cool to take a larger hexmap with already-assigned biomes and adapt this method to carve up the larger biome patches into smaller sub-biome blobs.

One suggested improvement: having temperature range from 1 to 5 results in maps that include both frozen tundra and steaming jungles -- which may work for some very fantastical worlds but strains credibility in others. I find I get better results when I manually edit the Ranomize_elev step to draw from 1-4 or 2-5.

The R Version

The basic functions of the terra implementation were as follows, recorded here on the off chance it's of use to anyone.

The die drop generates random points:

drop_locations <- spatSample(shape, size = die_count, method = "random")

Instead of intentionally dispersing points (as advised in the original post), we can implement Lloyd relaxation:

lloyd_relax <- function(points, extent){
  return(centroids(voronoi(points, bnd = extent)))
}

Then we can use inverse distance weighting interpolation to turn the points into a smooth surface, and then generate contours by rounding the surface to the nearest integer:

drop_surface <- interpIDW(r, drop_locations, field = "die_result", radius = hex_size_m*max(rc, cc), power=2.5)

We can then run that twice, use an intersect operation to overlay the maps, and then use a table join to assign biomes:

elev <- die_drop_countours(variable = 'elev', die = input$elevrange[1]:input$elevrange[2], shape=hexes, die_count = input$diecount, rc = input$rowcount, cc = input$colcount)
      
      temp <- die_drop_countours(variable = 'temp', die = input$temprange[1]:input$temprange[2], shape=hexes, die_count = input$diecount, rc = input$rowcount, cc = input$colcount)
      
      elev.temp.intersect <- terra::intersect(elev, temp) %>%
        mutate(elev.temp = paste(elev, temp, sep = ';'),
               zone_id = row_number()) %>%
        left_join(biomes) %>%
        group_by(zone_id) %>%
        slice_sample(n = 1)

And finally, we can sample the layer at hex centers to make a final hex map:

sampled_centroids <- terra::intersect(hex_centroids, elev.temp.intersect) 
      print(colnames(sampled_centroids))
    
      hexes <- hexes %>%
	      left_join(as.data.frame(sampled_centroids), by = c('id' = 'id'))

#DIY #GIS #random-tables