Perita

Autotiling Rules

Almost a year ago, we discussed the idea of a new role-playing game where players would scavenge derelict spaceships for loot. I thought it would be interesting to have players try to figure out where ships came from and why are now abandoned interspersed with turn-based fights; a sci-fi dungeon crawler, as it were. Unfortunately, we did not agree on how to develop it and the project itself became abandoned even before starting.

As a kind of New Year’s Resolution, i have decided to take on this project again, even if alone, and work on it a bit each day.

My intention is to develop a more traditional turn-based dungeon crawler, only in space, where the focus is on fighting enemies and navigating the interior of ships, that are the “dungeons”, with grid-based movement and optional permanent death. I am going to use oxygen levels in place of the usual starvation, and most weapons will be ranged, with their use of energy replacing mana, but other than that it will be fairly run-of-the-mill crawler.

However, i do not yet know how will the actual gameplay work—what will make it fun—and i have decided to start with what i am surely going to need: rendering ships’ decks. Just rendering, like in the following image.

Screenshot of a derelict ship’s deck

For the time being, until i write a dungeon generation algorithm, i keep these maps in text files that automatically reload every time i save. That way i can test out different configuration of tiles and see how the game renders them in real time without the need of a complicated map editor or to recompile and restart the game.

To make my life easier, i use the traditional plain text symbols to represent walls (#) and floor (·) tiles. Hence, the previous image was rendered from the following map.

#############··##########
#·······················#
#·······#####··#####····#
#·······#####··#####····#
####·######······###····#
####·#####········##·####
·························
·························
######·###········####·##
######·####······####···#
####·····####··######···#
####·····####··######···#
#######··####··######···#
#######················##
#############··##########

Rendering the floor is the easiest as, for now, i only have a single tile for it. Walls, on the other hand, require more consideration because of the way i made them this time.

In MLRL, ignoring variations, we used only two different kinds of walls: these that had more wall at the bottom, thus only the top part was visible; and these that had floor or empty space below, and therefore had to show the vertical part of the wall. Here is an example with the player’s sprite at each direction.

A mock-up of a MLRL’s floor with four players, each one at one cardinal direction.

For Xenorogue, however, i have decided to change the “camera angle”, as it were, and the vertical walls now use the full 16 pixels height of the tile. They are also taller and need a 8 pixel height tile on top to complete. Due to that, they overlap the floor that they have on top. Like in the following image.

A mock-up of a Xenorogue’s floor with the same four players, again each one at at cardinal direction.

All that means that i need more rules than just “is there more wall below?”. These rules could be described in Haxe, but then i would need to recompile the game each time i want to try a new rule, and once i have seen how easy is to hot-reload in Heaps i did not like the idea of wasting its potential. So, i have the rules in a text file next to the map’s file.

The format is very easy: each rule is an odd-sized square pattern, where each value of the pattern is a map symbol, such as # or ·, and, when the pattern matches, the game draws the asset whose name is written after the pattern, and stops testing rules for that position.

The easiest rules are the following.

#
wallF

.
floor

They mean “if you see a #, draw the asset named ‘wallF’, otherwise look if it is a · and draw the asset ‘floor’; if none match, leave it blank.” More complicated rules are like the following.

∀∀∀
·##
··∀
wall3

∀∀∀
##·
∀··
wall9

∀∀∀
·#∀
##∀
wall6

∀∀∀
∀#·
∀##
wallC

Here the symbol (“for all” or “for any”) is a wildcard and means “anything”, be it a wall, or floor, or an empty cell. Since the pattern is matched for the cell in the middle, these four rules represent the corners.

To allow for variations, i have added a “matching probability” for each pattern, that by default is 1 (i.e., always match), but can be lowered to match the pattern only some times.

∀∀∀
##·
∀··
wall9-brokenA
P=0.17

∀∀∀
##·
∀··
wall9

Here, the pattern for the broken wall will match only around 17 % of times, and stop the pattern matching process for that tile, so the lower rule will no paint over it. The 83 % of times that the first rule does not match, since the pattern is the same, the game will draw the regular corner.

And that’s all. Every time i save the file with the rules, the game reloads the map and the rules files, and redraws the whole level on the screen almost instantaneously, making it much easier to test new graphics and variations.