Build a Map

This page shows you how to assemble a playable level out of terrain entities: a Map that ties together a tile grid, a spawn point, and the actors placed on it when the level loads. By the end you can author a map and understand why it looks empty until an actor walks across it.

Prerequisites

You should be comfortable with the campaign data model before you build a map:

Fog of war: why a correct map looks blank

Before you build anything, you need to know that a freshly loaded map renders nothing. This is intended.

Every tile layer starts hidden. Each tile begins fully transparent over a dark, unexplored background. This is fog of war: the unexplored darkness that lifts only as an actor explores.

A tile reveals when an actor's discovery area overlaps it. That area is sized from the actor's perception field (see Create an actor). A hero with a small perception sees only the patch of terrain immediately around the spawn point when the level loads. The rest stays dark until the player moves.

Each tile is always in one of three states:

Discovery is tracked per actor and is saved with the game, so explored areas stay explored across sessions.

Note: If your map appears completely black after loading, that is normal. Move the player actor and the terrain fades in around it. A blank screen is not a sign that your tiles are wrong.

How a map fits together

A map is a small stack of entities, each with one job. The Map entity is the top of the stack and points at the rest by KeyRef:

Note: None of the fields below are required by the validator. In practice you set the ones you need for the map to function, and the example values show a working baseline.

Define the tiles

Start with the look of the terrain. A TileSet names a texture image inside the campaign and lays it out as a grid. The columns field tells the engine how wide that grid is, so it can turn each tile's index into a position in the atlas.

The example tile set uses an 8-column atlas and defines three tiles:

TileSet:
  demoTileSet:
    columns: 8
    texture: /assets/basic.png
    tiles:
    - grass
    - water
    - wall
Face:
  roof:
    northeast: true
    northwest: true
Tile:
  grass:
    symbol: G
    index: 0
    navigation: roof
  water:
    symbol: W
    index: 46
  wall:
    symbol: X
    index: 52
    obstacle: roof

Each Tile field controls one thing:

Tip: A tile defaults to neither walkable nor solid (both references absent). A floor tile you want actors to cross needs navigation pointing at a walkable Face, as grass shows. Reuse one Face entity (like roof) across many tiles.

Two more Tile fields exist for special cases. origin adjusts what draws in front, and ghost makes a tile invisible while it still blocks movement. Leave both off unless you have a specific need; the example uses neither.

Warning: Do not set ghost on your main floor tiles. A ghost tile is never drawn, so a ghosted floor leaves the terrain invisible.

Draw the layers

A Layer is a plain-text file of tile symbols, one character per cell. The file holds your map's shape: where the grass is, where the walls run, where there is nothing at all.

The grid format is deliberately simple. Each non-blank character is matched against a tile's symbol. Blank cells — a space, tab, newline, or empty position — place no tile, which is how you leave gaps. A short grass patch with a gap might look like this:

GGG
G G
GGG

Here the center cell is a space, so no tile is placed there.

The example splits its terrain across three layers, drawn in order from a TileMap:

TileMap:
  demoTileMap:
    tileset: demoTileSet
    layers:
    - demoFloor
    - demoWater
    - demoWalls
Layer:
  demoFloor:
    source: /demoMap/layer0
    ysort: false
  demoWater:
    source: /demoMap/layer1
    ysort: true
  demoWalls:
    source: /demoMap/layer2
    ysort: true

Each layer's source is a path to a grid file, relative to the campaign root. In the example these files live under a demoMap/ folder inside the campaign and have no file extension: layer0, layer1, layer2. The floor layer draws grass, the walls layer draws the maze border, and the water layer is blank in this map.

The ysort field controls what draws in front, so taller terrain like walls draws in front of what is behind it. Leave it off for a flat floor, as demoFloor does, and on for upright features.

Note: Layers draw in the order you list them. Put your floor first and features such as walls after, so the features sit on top.

How grid characters become tile positions

The engine walks the grid in a fixed direction. Each row advances the tile position by one step along the map's X axis, and each character within a row steps by one along the Y axis. You do not set these coordinates yourself; you only arrange characters in the file. The result is that the shape you type in the text file is the shape you walk in the game.

Place the spawn point

The player needs somewhere to enter. The Map's spawn field is a KeyRef to a Vector entity that holds an x and y position in pixels. It is the fallback location for the player actor when no saved position or action override applies.

The spawn Vector sits beside the Map entity in the same file:

Vector:
  demoSpawn:
    x: 128
    y: 16

The Map refers to it by key, as the assembled Map below shows.

Deploy non-player actors

A Deployment places one non-player actor on the map when the level loads. Each deployment pairs an actor to spawn with a location Vector that says where. The engine spawns each deployed actor as an NPC.

The example places three NPCs:

Deployment:
  guardDeploy:
    location: guardPos
    actor: guardActor
  merchantDeploy:
    location: merchantPos
    actor: merchantActor
  patrollerDeploy:
    location: patrollerPos
    actor: patrollerActor
Vector:
  guardPos:
    x: 128
    y: -48
  merchantPos:
    x: 160
    y: 32
  patrollerPos:
    x: 288
    y: 0

Each actor is a full Actor entity defined elsewhere in the campaign. To give a deployed NPC its own behavior, give that actor a strategy; see Add NPC AI.

Assemble the map

With the tiles, layers, spawn, and deployments in place, the Map entity ties them together:

Map:
  demoMap:
    name: Demo Map
    tilemap: demoTileMap
    spawn: demoSpawn
    deployments:
    - guardDeploy
    - merchantDeploy
    - patrollerDeploy
Vector:
  demoSpawn:
    x: 128
    y: 16

This Map names itself for the interface, draws its terrain from demoTileMap, enters the player at demoSpawn, and deploys the three NPCs. To make this map the one a campaign starts on, point the Main entity's map field at it; see Campaign structure.

The Map also carries background and audio fields for parallax scenery and music. Those are covered in Audio and backgrounds.

Add floor overlays (optional)

A Floor draws a single texture image at a fixed position, beneath the tiles. Use it for a backdrop or a decorative surface that the tile grid sits on top of. A Floor has a texture path and a location KeyRef to a Vector for its top-left corner. The Map's floor field lists the floor overlays to draw. The example map uses none, so you can skip this until you need a painted backdrop.

Verify the map loads

Zip your campaign and check that the map loads and validates:

./isometry --validate=/path/to/mygame.zip
./isometry --campaign=mygame --network=host --port=5000 \
  --username=p --secret=p --log-level=INFO

A successful load logs Campaign validation passed and Successfully created Entity lines. Remember the fog of war: a loaded map looks dark until an actor's discovery area reveals the tiles near it.

See also