After researching countless articles and techniques, I've finally arrived a a nice dynamic solution for tile transitions. There are multiple issues and gotchas when researching the topic and after not properly grasping some already very extensive writeups I thought I'd combine everything I've learned over the last few weeks into a single comprehensive blog post series.

The basics

To get a better understanding of the topics I'm about to cover you should be familiar with the terms tilemap, tileset and autotile. If you are, just skip ahead to the next section, otherwise I'll cover most of the basics now.

What are tiles?

Especially in earlier years of game development, but currently reliving a great renaissance through the indie scene, tile-based games were found all over. By tiling your game world you are essentially dividing it up into a grid of regular shapes. There's different shapes for different needs. Squares usually work best for top-down games like the early GameBoy Pokémon adaptations or the Harvest Moon series.

Harvest Moon Screenshot.
Harvest Moon for the GameBoy without visible tile transitions (Source).

Other types of tile shapes include hexagonal (Civilization series) or isometric tiles (Rollercoaster Tycoon). This series will focus on square tiles only, but can be adapted to any tile shape.

The most common concepts in tile-based games include:

Tilesets
Storing all tile graphics in separate textures would introduce unnecessary overhead. So tiles used commonly together are stored in a single texture called a tileset. Selection of a single tile based on coordinates is explained further down in this post.

Tilemaps
Tilemaps store all tiles of your world. This is usually done via array indexing in either a single- or multi-dimensional array:

// Single-dimensional array improve performance and required storage capacity...
var tilemap = new int[width * height];
var tile = tilemap[x + y * width];

// ... while multi-dimensional arrays are sometimes easier to work with.
var tilemap = new int[,];
var tile = tilemap[x, y];

Using multi-dimensional arrays might sometimes be slower.

Tile transitions
As you can see in the Harvest Moon screenshot above, square tiles without any transitions can look quite jarring. They also obviously can't hide the fact that your entire world is grid-based. That's why we'll look at ways to transition smoothly from one tile type to another.

Automatic tile transitions hide the grid base of your world (Source).

Transitioning tiles