Tile-Based Level Design in Phaser 3 with the Tiled Editor


A tilemap lets you build a game level by arranging reusable images instead of placing every floor tile, wall, and decoration by hand. In this guide you will author a Tiled map for Phaser 3.90, wire up tile collisions, and learn three mistakes to watch for in AI-generated tilemap code.

Credibility: This guide is desk research from the official Phaser and Tiled documentation and published Phaser examples; it does not claim hands-on benchmarking.

What Phaser 3.90 changed about tilemap layers

Phaser 3.90 treats a Tilemap as a data container, not a display object. It parses map data from Tiled JSON, CSV, or a two-dimensional array. Since Phaser 3.50, rendering uses unified TilemapLayer objects made with createLayer, replacing the separate static and dynamic layer APIs.

A TilemapLayer is a Game Object responsible for rendering one layer of tile data. The Phaser Tilemap docs describe the map as data you populate with tilesets and layers; the TilemapLayer docs explain the rendering role of each layer. Think of the map as the level’s organised data and its layers as the visible parts of that level.

Phaser supports Orthogonal, Isometric, Hexagonal, and Staggered orientations. For a first project, Orthogonal is the straightforward choice: tiles line up in a familiar grid. Tilemap layers handle camera culling themselves, so only visible tiles are sent to the renderer each frame, and they support both Arcade Physics and Matter.js.

AI mistake 1: using removed layer methods. Older examples and generated answers may suggest createStaticLayer or createDynamicLayer. Those belong to the pre-3.50 API. Use the current map.createLayer(...) call instead, and correct any generated code that mixes the old and new APIs.

Set up a Tiled tileset image and export JSON

Tiled is a 2D level editor whose primary feature is editing tile maps. For Phaser, choose a “Based on Tileset Image” tileset, where regularly sized tiles are cut from one image. Export the map as Tiled JSON and embed the tileset definition, so Phaser can connect tiles to layers.

Start with a single tileset image containing the terrain and other tiles you plan to use. In Tiled, create a tileset based on that image, set the tile dimensions to match the artwork, and give the tileset a clear name. The name matters later: Phaser matches the tileset by the name you assign in Tiled. The Tiled tileset guide covers the available tileset types and the editing workflow.

Save the tileset as its own file, which is Tiled’s recommended default since version 1.0. Then create a map, add tile layers such as Ground and Walls, and paint the level. Layer order determines rendering order; layers also support offsets, tint, blend modes, and parallax scrolling. A lower parallax factor makes a layer appear farther away. See Tiled’s layers guide for layer behaviour.

For collision, add a boolean custom property named collides to the tiles that should block the player. You can set tile properties in Tiled and have Phaser select the matching tiles. Tiled’s Tile Collision Editor also lets you draw collision shapes on tiles, but a simple boolean property is a clear starting point.

When you export, keep the tileset embedded in the exported map data. Phaser’s parser does not support the “Collection of Images” tileset type, where every tile is its own image file.

AI mistake 2: a “Collection of Images” tileset. An assistant may recommend splitting tiles into separate images because that reads as tidier. Phaser’s Tiled parser cannot load that: you must keep the tiles for a layer inside one tileset image and embed the tileset in the map JSON. The Tiled manual covers map creation and export.

Load a Tiled JSON tilemap in Phaser 3

Load the tileset image and the Tiled JSON during the scene’s preload step, then build the map and its rendered layer in create. The image key is a Phaser asset key; the tileset name is the name you gave the tileset inside Tiled. Keeping those identifiers distinct prevents a common setup error.

The loading calls below belong in a scene’s preload method. In create, make the tilemap from the JSON key, connect it to the loaded image, and create the layer whose name matches the layer in Tiled:

preload() {
  this.load.image('tiles', 'assets/tileset.png');
  this.load.tilemapTiledJSON('map', 'assets/level1.json');
}

create() {
  const map = this.make.tilemap({ key: 'map' });
  const tileset = map.addTilesetImage('TilesetNameInTiled', 'tiles');
  const ground = map.createLayer('Ground', tileset, 0, 0);
}

AI mistake 3: swapping the arguments to addTilesetImage. Its first argument is the Tiled tileset name, and its second is the Phaser image key. In the example, TilesetNameInTiled must match the name in Tiled, while tiles is the key used in this.load.image. Check both values against their real sources before running the scene.

Layer names must match the names in the exported map. If you place a layer inside a Tiled group, note that Phaser flattens group layers, so a child layer may appear under a name such as ParentGroup/Layer 1 rather than its own name. If a layer lookup fails, inspect the exported layer names before rewriting the code.

Add collision, world bounds, and object spawns

After creating a layer, set collision on the tiles that should block the player, then register that layer as a physics collider. Set camera and physics bounds from the map’s pixel dimensions, and use object layers for things like spawn markers.

For property-based collision, the map needs tiles carrying a boolean collides property. The call below follows the property-based method shown in Phaser’s example:

ground.setCollisionByProperty({ collides: true });
this.physics.add.collider(player, ground);

this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.cameras.main.startFollow(player, true);

Here map and ground are the variables from the previous section, and player is a player object already created in your scene. Phaser also offers setCollision, setCollisionBetween, setCollisionByExclusion, and setCollisionFromCollisionGroup. Pick the method that matches how your tiles are marked, and avoid stacking several methods without a reason.

You can mark spawn points on an object layer in Tiled, then create them in code from their object name. The call below builds sprite objects from entries named spawn in a layer named Objects, using the same player image key loaded in preload:

const [player] = map.createFromObjects('Objects', {
  name: 'spawn',
  classType: Phaser.Physics.Arcade.Sprite,
  key: 'player'
});

Confirm that the object-layer name and object name in Tiled match the values in the call. Object layers can hold rectangles, points, polygons, tile objects, and text, each with custom properties, which makes them useful for level information that painted tiles cannot carry.

Choose your approach: Tiled JSON vs CSV/2D array vs plain sprites

Choose Tiled JSON when you want to edit a level visually with layers, tileset properties, and object markers. CSV or a two-dimensional array is simpler for a small grid stored as data. Plain sprites suit individual objects that need separate placement or behaviour.

Tiled JSON CSV / 2D array plain sprites
Best for: levels you author visually in Tiled, with named layers and object markers. Best for: a small, fixed grid you already hold as rows and columns of tile values. Best for: a handful of items or scenery that each need separate placement.
Strengths: layers, tileset data, object layers, and a visual editing workflow. Strengths: compact and easy to generate or edit as plain data. Strengths: full per-object control over position and behaviour.
Limits: needs a tileset and a Tiled export step. Limits: no visual editing and no object metadata. Limits: becomes unwieldy once a level contains many repeated tiles.

Phaser parses map data from a Tiled JSON file, a CSV file, or a two-dimensional array, as its Tilemap docs state. A tiny array might look like this:

const grid = [
  [1, 1, 1, 1],
  [1, 0, 0, 1],
  [1, 0, 1, 1],
  [1, 1, 1, 1]
];

That array is only map data: it carries no tileset, display layer, or collision setup. If you want visual editing and named objects, Tiled JSON gives you those authoring features. If your level is a small fixed grid, an array may be enough. Do not reach for plain sprites just to work around a tileset setup mistake — for repeated terrain, a tilemap is the purpose-built option.

FAQ

Tilemap setup gets easier when you separate authoring from runtime: Tiled describes the map, while Phaser loads that data and renders its layers. These answers cover the beginner questions that come up most often before you grow a first level.

Which Tiled tileset type should I use with Phaser?

Use a “Based on Tileset Image” tileset, where the tiles are cut from a single image, because that matches Phaser’s Tiled parser requirements. Do not use “Collection of Images” for a Phaser Tiled map, since that feature is unsupported by the parser. Export the map with the tileset embedded in the Tiled JSON data.

Why does my generated code call a layer method that Phaser does not recognise?

An AI assistant may have learned from older Phaser examples that use createStaticLayer or createDynamicLayer. Those are pre-3.50 methods, not the current approach. Phaser 3.90 uses the unified TilemapLayer class, so create a layer with map.createLayer(...) and check that the layer name matches the map.

Why does addTilesetImage fail even though my image loaded?

The image can load successfully while the tileset connection is still wrong. The first argument to addTilesetImage must match the tileset’s name in Tiled, and the second must match the Phaser image key used when loading the image. Check both values, then confirm the map contains the named tileset.

What you learned

A Phaser tilemap is data connected to tileset images and rendered through layers, so a working level depends on matching names and compatible assets as much as on code. Tiled provides the authoring workflow; Phaser 3.90 provides the runtime layer and collision APIs.

  • Use TilemapLayer and map.createLayer(...) in Phaser 3.90, not the removed pre-3.50 layer methods.
  • Make the first addTilesetImage argument the Tiled tileset name and the second the loaded image key.
  • Keep each layer’s tiles in one tileset image and embed the tileset in the exported Tiled JSON.
  • Mark blocking tiles with a property such as collides, then set collision on the matching layer.
  • Compare Tiled layer and object names with the names used in your Phaser code.