Automatically creates & tiles .tmx format maps from a world map interface

Autotile

Create tiled maps for an arbitrarily large world space from a simple interface, then add larger objects randomly with simple rules (eg. place trees but only on grass/dirt tiles).

example beach scene

Why

Creating maps by hand is labourious and annoying. Especially if you have a few different tilesets for various biomes that need to be placed the same way. A clear river running through an idyllic valley, a murky river through a swamp, a frozen river in the dead of winter - they all have the same tile pieces; centres, left turns, right turns, corners .. like a great jigsaw .. why place these things by hand when a machine can do it (even if it's just to get you started!).

What

Autotile is intended to place various elements tile by tile on to map(s) from something that implements a simple interface. Including complex things with tiles that dove tail together & can vary in shape; rivers, waterfalls, cliffs, lava, roads / paths. As well as simple land tiles - snow where it is cold, sand on beaches & in deserts, grass, dirt etc. And larger logical objects composed of tiles themselves (eg. trees, rocks, houses & anything really).

For the later, placing larger logical objects, this uses & is designed to be used with my tile library which includes tooling to disect larger images in to smaller layered maps. For more info & a tool to create compatible 'tobs' please check that readme or see some of the examples under tobs. Tl;dr they're essentially tiled TMX maps with some special properties.

How

Base Maps

Firstly we'd like to create the base maps. By 'base' I mean we want to place all of the landscape type tiles - land tiles like grass, snow, dirt, water, cliffs, lava, waterfalls etc.

In order to do this we supply something that satisfies the Outline interface (don't panic, it's pretty short).

// tell me how large the world map is 
Bounds() image.Rectangle

// tell me what the area is like at world co-ords (x, y)
At(x, y int) *Area

An Area just relates some basic info like

  • height at the given location
  • average temperature
  • whether the given point has water (sea, river, swamp), lava, road etc
  • a Land struct that tells us what tile(s) to place at this location
  • optional tags ([]string) to add to tiles sourced from this location

Nb. it's recommended not to re-create a Land struct (or even Area if possible) each time At is called -- we'll be calling this function a lot & having it re-instantiate an object each time is probably more work than we want to do.

Armed with this & some config information we can begin creating maps. Checkout the example.

Placing Objects

To place tile objects (again, see

  ldr := autotile.NewFileLoader("")
  bin := autotile.NewObjectBin(ldr)
  
  bin.Load(
    "trees",  // load a new group called "trees"
    0.4,      // we should place an item from the group "trees" 40% of the time
    []string{"tree.01.tmx", "shrub.01.tmx"}, // here are the trees that the Loader (above) knows how to load
    nil,
    []string{autotile.Dirt, autotile.Grass}, // items from group "trees" can be placed only on Dirt or Grass tiles
  )
  
  bin.Load(
     "",      // empty string represents the nil group; ie the chance we place nothing at all
     0.6,     // %60 chance we don't place any object on a given tile
     nil, 
     nil, 
     nil,
  )
  
  // where `m` is a MapOutline returned from CreateMaps and `at` is an autotiler from NewAutotiler()
  at.AddObjects(m, bin)

Again checkout the example for more details.

Notice a couple of things

  • the Loader here in an interface with one function that loads a TMX map given some string. The most trivial example is FileLoader (where the key is a file path) but of course you can supply your own loader that does whatever
  • we can control what tiles the bottom (lowest z-layer) of the object sits on with the last two args all and any which both take a list of tags ([]string)
  • these tags are added at map creation time & as mentioned before the user can stipulate their own (by setting on an Area struct)

Finally we can save out the resulting maps with a simple

	m.Tilemap.WriteFile("my-map.tmx")

It's uh, recommended to not try to keep thousands of maps in memory at a time & to write the out ASAP.

The World

The intention then is to turn a high level world map (depicting rivers , sea, height information, temperature, rivers, sea etc) into an arbitrarily large number of fully tiled maps, each of them representing some (x,y) offset chunk of the world space with fairly minimal work on our part.

TODO

There's more to come in this space -- I'd like to handle creating interiors, cities & villages, cave systems etc. Feel free to push up PRs, requests, fixes etc.

Credits

The image(s) used here are taken from pokemon gen5 tilesets from deviantart and/or spriters resource. Some have been created from existing tiles where original pieces didn't exist. I've added them as an example & a way to visually test code changes.

Similar Resources

Go library for decoding generic map values into native Go structures and vice versa.

mapstructure mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling. This l

Dec 28, 2022

a thread-safe concurrent map for go

concurrent map As explained here and here, the map type in Go doesn't support concurrent reads and writes. concurrent-map provides a high-performance

Jan 8, 2023

Fast integer map for uint32-to-uint32

Fast integer map for uint32-to-uint32

Uint32-to-Uint32 Map This repository contains an implementation of uint32-to-uint32 map which is ~20-50% faster than Go standard map for the same type

Sep 21, 2022

A thread-safe concurrent map for go

concurrent map Original repo didn't support go mod and no any tags,so I forkd this repo add go mod support and patch a tag on this repo. No any code c

Dec 7, 2021

read copy update map for golang 1.18+

(R)ead-(C)opy-Update read copy update map for golang 1.18+ How it works This is a simple generic implementation for https://en.wikipedia.org/wiki/Read

Dec 11, 2022

Experimenting with golang generics to implement functional favorites like filter, map, && reduce.

funcy Experimenting with golang generics to implement functional favorites like filter, map, && reduce. 2021-12 To run the tests, you need to install

Dec 29, 2021

Map downloader and configurator for KillingFloor 2

kf2-map-config Copy the kf2-map-config.exe and maps.txt into the Killing Floor2

Jul 2, 2022

Q2entities - Parse the entities string from a Quake 2 .bsp map file. Written in Go

Q2Entities A simple command-line utility to extract the entities string from a Quake 2 map file. Entities? Binary Space Partitioning maps (.bsp) conta

Apr 9, 2022

Goterators - A util library that Supports aggregate & transforms functions Go. Such as filter, map, reduce, find, exist

Goterators - A util library that Supports aggregate & transforms functions Go. Such as filter, map, reduce, find, exist

Goterators Goterators is util library that Supports aggregate & transforms functions Go, including: for-each find exist reduce filter map API and func

Dec 19, 2022
Related tags
💪 Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more.
💪 Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more.

?? Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more. Go 的一些工具函数,格式化,特殊处理,常用信息获取等等

Jan 6, 2023
Creates Prometheus Metrics for PolicyReports and ClusterPolicyReports. It also sends PolicyReportResults to different Targets like Grafana Loki or Slack
Creates Prometheus Metrics for PolicyReports and ClusterPolicyReports. It also sends PolicyReportResults to different Targets like Grafana Loki or Slack

PolicyReporter Motivation Kyverno ships with two types of validation. You can either enforce a rule or audit it. If you don't want to block developers

Aug 6, 2021
A Go package for checking conditions for slices and maps.

check Go package The check package of Go helps one to check various conditions for slices: []int []float64 []string []bool maps: map[string]int map[st

Aug 26, 2022
Cell is a Go package that creates new instances by string in running time.

Cell Cell is a Go package that creates new instances by string in running time. Getting Started Installing To start using CELL, install Go and run go

Dec 20, 2021
Create deep copies (clones) of your maps and slices without using reflection.

DeepCopy DeepCopy helps you create deep copies (clones) of your maps and slices. Create deep copies (clones) of your objects The package is based on t

Nov 20, 2022
Access and modify property values in deeply nested maps, using dot-separated paths

Dig lets you access and modify property values in deeply nested, unstructured maps, using dot-separated paths: source := make(map[string]interface{})

May 7, 2022
ms - 'my story' creates a secure password string which can be memorized with a technique shared by Max.

On 23.12.21 20:22, Stefan Claas wrote: [...] > > Yes, I am aware of that, but how can one memorize a key when traveling > and not taking any devices

Dec 24, 2021
Golang: unify nil and empty slices and maps

unifynil, unify nil and empty slices and maps in Golang Empty slices and maps can be nil or not nil in Go. It may become a nightmare in tests and JSON

Jan 16, 2022
🍕 Enjoy a slice! A utility library for dealing with slices and maps that focuses on type safety and performance.

?? github.com/elliotchance/pie Enjoy a slice! pie is a library of utility functions for common operations on slices and maps. Quick Start FAQ What are

Dec 30, 2022
Go library to interface with NEAR nodes' JSON-RPC interface

StreamingFast Solana library for Go Go library to interface with NEAR nodes' JSON-RPC interface Contributing Issues and PR in this repo related strict

Nov 9, 2021