Skip to content

Godot Tileset Collision — Physics Polygons from Tile Alpha

Drawing a collision shape on each of 47 tiles in Godot's TileSet editor is slow, and one pixel off is enough for a character to snag on a seam. The Tile workspace traces the shape from each tile's alpha, lets you drag the points that are wrong, and hands Godot a physics layer built by its own import script.

In Godot 4, tile collision lives in the TileSet: add a physics layer (its collision layer and mask), then give each tile one or more collision polygons; the points are measured from the tile's centre. Nerulio traces a polygon for every tile from its alpha (outline, exact rectangles or one box), lets you move the points, and its import script writes physics layer 0 with collision layer 1 and mask 1 and each polygon shifted by half a tile. Godot 4.7.2 read every polygon back point for point.

Drop a tileset or autotile sheet (PNG)
Runs in your browser. Files are not uploaded.
Studio Tile workspace: a CC0 blob-47 tileset (16 px) with a collision polygon traced from the alpha of every tile
The real Studio with a CC0 asset (OpenGameArt).
Exports to
  • Godot 4 TileSetVerified· Godot 4.7.2
  • TiledVerified· Tiled 1.12.2
  • Unity 6 Rule TileVerified· Unity 6000.5.3f1 + 2D Tilemap Extras 8.0.3
  • LDtkPartly verified· LDtk 1.5.3 schema + loader

Physics layers, polygons and the tile centre

A TileSet has a list of physics layers, each with a collision layer, a collision mask and optionally a physics material (the Godot docs: TileSet inspector › Physics Layers › Add Element). Per layer every tile can hold several polygons (TileData.set_collision_polygon_points(layer, index, points)), each optionally one-way. A TileMapLayer turns the painted tiles into static collision as long as its collision_enabled is on (the default).

Nerulio keeps shapes in tile pixels with the origin at the tile's top-left, the way you draw them. Godot measures a tile's polygon from the tile centre, so the importer subtracts half the tile size from every point. A tool that skips this shift puts every shape half a tile up and left.

Three readings of the alpha (a pixel counts as solid when its alpha is above 0): Outline follows the solid edge along pixel borders and keeps only outer loops, so a hole becomes solid; Exact rectangles covers exactly the solid pixels with a few boxes, holes stay open; Box is one rectangle around everything. A long outline is simplified until it has at most 256 points.

Physics layer
A slot on the TileSet with collision layer, mask and material; tiles store polygons per slot.
Collision polygon
A list of points around the tile centre; everything inside counts as solid.
Collision layer / mask
Which layers the tiles are on, and which layers they detect; a body collides with the tiles when its mask includes their layer.
Half-tile shift
Top-left tile pixels minus (width ÷ 2, height ÷ 2) = Godot's centred coordinates.

Example: a 64 px ground tile, from pixels to Godot

64 × 64 tile, solid ground in the lower 40 px (pixel rows 24–63)
Nerulio, tile pixels (origin top-left)   (0,24) (64,24) (64,64) (0,64)
half tile = (32, 32)
Godot, from the tile centre              (-32,-8) (32,-8) (32,32) (-32,32)
importer  TileData.set_collision_polygon_points(0, 0, points)   physics layer 0, polygon 0
TileSet   physics layer 0: collision_layer 1, collision_mask 1

A CharacterBody2D stands on this tile only if its collision_mask includes layer 1; change the TileSet's layer numbers after import if your project uses others.

What it does

  • Three readings of a tile's alpha: Outline polygon follows the solid edge, Exact rectangles covers only the solid pixels with axis-aligned boxes, Box wraps everything in one rectangle.
  • Shapes live in tile pixels, snapped to whole pixels: drag a point, double-click an edge to add one, Alt+click to remove one. Every edit is one undo step.
  • Show shapes of every tile draws all polygons over the sheet at once, so a gap between two neighbouring tiles shows up before you export.
  • On export, the shapes you edited stay exactly as they are; the collision mode you pick fills in the tiles you never touched, from their alpha.
  • nerulio_tileset_import.gd adds one physics layer (collision layer 1, mask 1) and writes each polygon onto its tile, shifted by half a tile because Godot measures tile shapes from the tile centre.
  • Checked by reading the TileSet back in Godot 4.7.2: every polygon matched point for point — 49/49, 48/48 and 47/47 tiles on the corpus blob sets, 80/80 on a four-terrain dual-grid pack.

How to do it

  1. Drop the tileset and press Use this grid.
  2. Apply a layout or paint terrain bits; only tiles with bits can carry a shape.
  3. Press C, pick a tile, trace it as Outline polygon, Exact rectangles or Box, and drag any point that sits wrong.
  4. Open Export (Ctrl+E), tick Godot 4 and choose the collision mode for untouched tiles.
  5. In Godot, run nerulio_tileset_import.gd with File › Run and put the saved TileSet on a TileMapLayer.

Files you get

Collision travels inside the Godot files of the export:

FileWhat it is for
nerulio-tileset.jsonphysicsLayers (collision layer 1, mask 1, the mode used) and, per tile, collision: polygons in tile pixels.
nerulio_tileset_import.gdAdds the physics layer and writes each polygon with the half-tile shift; its Output line counts the polygons.
nerulio-tileset.tresSaved by Godot when the script runs: the TileSet with terrains and collision.

Get the collision into Godot and test it

  1. In Nerulio's Export panel set Collision (Godot) to Outline polygon, Exact rectangles, Box or Only edited shapes. The default is None, which writes no physics layer at all — even for shapes you edited.
  2. Copy the PNG, JSON and script to the project root, run the script with File › Run, and check the Output line, for example … 47 tiles, 188 peering bits, 47 collision polygons ….
  3. Load nerulio-tileset.tres into a TileMapLayer's Tile Set property and paint.
  4. Give your player body a collision_mask that includes layer 1 (or change physics layer 0's collision layer in the TileSet inspector to the layer your project uses).
  5. Turn on Debug › Visible Collision Shapes and run the scene: the shapes are drawn over the tiles while the game runs.
  6. One-way platforms or a physics material: in the TileSet editor, Select mode, click the tile and edit its Physics Layer 0 section; press F there for a quick full-tile rectangle.

Check the result

  • The script's Output line counts as many collision polygons as you expect (one per tile for Box and most Outline shapes).
  • TileSet editor › Select mode › click a tile: the Physics Layer 0 section shows the polygon on the art.
  • With Visible Collision Shapes on, the top edges of neighbouring ground tiles form one continuous line, and a tile with a gap shows the gap when you used Exact rectangles.
  • print($TileMapLayer.tile_set.get_physics_layer_collision_layer(0)) prints 1.

Collision modes and what Godot receives

ModeShape writtenHolesGood for
Outline polygonThe traced outer edge along pixel borders, one polygon per solid islandFilled (outer loop only)Slopes, rounded ledges, irregular rock
Exact rectanglesA few axis-aligned rectangles that together cover exactly the solid pixelsStay openTiles with a gap, L shapes, notched platforms
BoxOne rectangle around every non-transparent pixelFilledFull blocks, crates, cheap physics
Only edited shapesYour hand-edited polygons; other tiles get noneAs you drew themSets where only a few tiles should collide
NoneNo physics layer at all—Decoration-only tilesets

A fully opaque tile becomes one tile-sized square under Box and Exact rectangles. A long outline is simplified until the tile holds at most 256 points.

Troubleshooting

SymptomLikely causeHow to checkFix
The TileSet has no physics layerCollision (Godot) was left on None in the exportOutput line: 0 collision polygonsChoose a collision mode and export again
The player falls through the tilesThe body's mask does not include layer 1, or the layer's collision_enabled is offInspector of the body and of the TileMapLayerAdd layer 1 to the mask, or set the TileSet's physics layer to your project's layer
Shapes sit half a tile up and leftThe polygons came from a tool that wrote top-left coordinates without the shiftVisible Collision ShapesRe-import with Nerulio's script, which applies the shift
A tile with an opening is fully solidOutline keeps only the outer loopThe tile's polygon in the TileSet editorUse Exact rectangles for that set, or edit that tile's points
The character catches on seams between tilesNeighbouring polygons end at different heights by a pixelVisible Collision Shapes, zoomed in on the seamUse Box or Exact rectangles for full tiles, or drag the points level in the Studio's collision tool (C)
Some tiles have no shapeOnly tiles with terrain bits are exported, and an alpha of 0 everywhere gives no shapeStudio: tiles without bits are dimmedPaint bits for those tiles, or draw their shape by hand in Godot

Other ways to do it

OptionWhen it is the better choice
Draw the polygons in Godot's TileSet editor (F for a full rectangle, then add or remove points; tile property painting copies one shape onto many tiles)Full blocks and a few slopes; no extra tool, but each shape is placed by hand.
Sprite collision instead of tiles: collision polygon generatorThe shape belongs to a character or prop, not to a tile in a TileSet.
Unity Rule Tiles with Collider set to Grid: Unity Rule TileYour target is Unity; Nerulio's traced polygons are written for Godot only.

Engine exports and how each was checked

"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.

TargetFilesCheck
Godot 4 TileSetPNG · nerulio-tileset.json · nerulio_tileset_import.gdVerified Godot 4.7.2The included import script builds the TileSet with terrain peering bits; a map painted with set_cells_terrain_connect equals the Studio preview in every cell on 9 corpus sheets.
Tiled.tsx Wang set · sample.tmxVerified Tiled 1.12.2Tiled's own readers load every Wang ID as written and the sample map renders pixel-exact. The terrain brush itself was not driven.
Unity 6 Rule Tilenerulio-ruletile.json · Editor/NerulioRuleTileImporter.csVerified Unity 6000.5.3f1 + 2D Tilemap Extras 8.0.3Blob and side sets: a painted Tilemap shows the predicted sprite in every cell. Corner / dual-grid sets are not exported to Unity.
LDtk.ldtk (1.5.3) · rules · sample levelPartly verified LDtk 1.5.3 schema + loaderAccepted by the LDtk JSON schema and its official loader, and the rules re-run to the exported tiles; not opened in the LDtk app.

Evidence

Layouts identified from the pixels alone on the tile corpus: 4 blob-47 templates and 2 Wang templates with high confidence, a real 64 px cave tileset with medium confidence — every tile's bits right. Godot 4.7.2 painted every test cell exactly as the Studio predicted (485/485 per blob set, 251/251 on a 4-terrain dual-grid pack); Tiled 1.12.2 read every Wang ID back; Unity 6000.5 matched on every painted cell of the blob and side sets.

Limits

  • One physics layer, plain polygons: one-way flags, extra layers and physics materials are set in Godot afterwards.
  • Holes are exact only with Exact rectangles.
  • Tiles without terrain bits get no collision in the export.
  • Tiled's terrain brush, the LDtk app and Godot's editor painter were not driven; the checks use the engines' readers and set_cells_terrain_connect.
  • Unity gets blob and side sets only; several terrains become several Rule Tiles with no transitions between them.
  • Isometric and hex tiles, animated tiles, occlusion and navigation layers are out of scope.
  • Suggesting bits without a known layout needs a reference "full" tile; on side-only path templates the guess can fail until you select it.

Versions and sources

Checked in Godot 4.7.2 by reading the saved TileSet back: every polygon matched point for point after the half-tile shift — 49/49, 48/48 and 47/47 tiles on the corpus blob sets, 16/16 on the edge and corner templates, 80/80 on a four-terrain dual-grid pack. Editor steps follow the Godot 4.7 documentation.

Official documentation used

Questions

My character falls through the floor. Is the physics layer there?

The import script adds a physics layer only when at least one tile has a shape, and sets it to collision layer 1 and mask 1. Your body's collision mask has to include layer 1; if your project uses other layer numbers, change them on the TileSet after import.

Why does a tile with a hole come out fully solid?

Outline polygon keeps only the outer loop, and Godot treats the inside of every polygon as solid, so the hole fills in. Exact rectangles covers just the solid pixels, so the opening stays open.

Can I set one-way platforms or per-tile layers here?

No. The export writes one physics layer with plain polygons. One-way collision, extra layers and physics materials are set in Godot's TileSet editor once the set is imported.

Is collision also written for Unity, Tiled or LDtk?

No, collision goes to Godot only. The Unity Rule Tile, Tiled and LDtk exports carry the tiles and their rules without shapes, and tile collision inside Unity was not checked.

Is it free, and do I need an account?

Everything on these pages is free and works without an account. There is no watermark and no export that is held back.

Are my sprites uploaded?

No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.

Does it need Aseprite or an engine plugin installed?

No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).