An LDtk-style 2D tile-map editor and runtime for Unreal Engine's Paper2D: rule/bitmask auto-tiling, exact-tile stamps, depth-parallaxed backgrounds, per-tile collision shapes, and native Box2D 2D physics for tile collision — in one plugin.
Built and tested against Unreal Engine 5.8.
- Unreal Engine 5.8. The
.upluginpinsEngineVersion: 5.8.0; the plugin is built and tested against that version only. - Paper2D and ProceduralMeshComponent — both enabled automatically via the
.uplugin's ownPluginslist. - Windows (Win64) is the primary, fully supported platform. A Linux static Box2D
library (
Source/ThirdParty/Box2DLibrary/lib/Linux/libbox2d.a) is vendored alongside the Win64 one (lib/Win64/box2d.lib), so a Linux dedicated-server build links too. macOS and every other platform have no vendored library and are unsupported. - No
PlatformAllowList, by design.TileMapPlus.uplugindeclares none, so UBT will configure the whole plugin for whatever platform a host project targets. Rather than let an allowlist silently drop the plugin on an unsupported platform,Box2DLibrary.Build.csfails the configure step loudly and by name for anything besides Win64 and Linux — a Mac target gets an explicitBuildException("Box2D Mac library not provided — the Mac target is unsupported.") instead of a plugin that quietly isn't there. - A C++ project is required to build from source; this repository is not a Blueprint-only drop-in.
From Fab — once listed, install through the Epic Games Launcher and enable TileMap Plus in Edit → Plugins.
From source — clone (or copy) into your project's Plugins/ directory:
YourProject/
YourProject.uproject
Plugins/
TileMapPlus/
Right-click the .uproject → Generate Visual Studio project files, then build.
- Create — Content Browser → Add → TileMap Plus Asset, or open the asset editor's
Map menu → Open Sample… to start from one of the bundled samples in
Content/Samplesinstead. - Paint — pick a tile set in the Palette tab, choose a brush from the toolbar (Paint, Rectangle Fill, Flood Fill, Random Scatter, Stamp, Eraser, Entity, Eyedropper, or Select), and paint on the active layer in the Viewport. Stack (Shift+T) isn't a brush — it's a toggle: turn it on and a paint click stacks tiles onto the cell instead of replacing them, and it coexists with whichever brush is active.
- Rules — open the Rule Editor tab, give a rule set a Mode (Off, Cardinal · 16, Blob · 47, or Full · 256) and a tile set, then assign tiles on the 3×3 neighbour grid. Add Missing creates one rule per uncovered pattern and the coverage counter tracks how much of the mode is defined. Stamps with Exact Tiles also work against an Off-mode rule set — the exact tile survives resolves even with no auto-tiling defined.
- Stamps — build a multi-cell arrangement once (a tree, a house, a fence) and place it in a single click with the Stamp brush. Give it Exact Tiles so every cell keeps its own authored art instead of resolving through the rule set.
- Layers — the Layers tab lists ordinary tile layers plus collapsible Auto-Layers and Backgrounds sections. A background gets its own Depth, so a perspective camera parallaxes it; both layers and backgrounds are fixed in the level's space unless you switch on their Enable Parallax.
- Collision — a layer's Collision Settings choose a Shape Source (Full Cell, or the
tile set's own per-tile shapes authored in the Paper2D Tile Set editor) and a physics
backend: Chaos, or native Box2D via the
TileMapPlusBox2Dadapter.
- Rule/bitmask auto-tiling — Cardinal · 16, Blob · 47, or Full · 256 neighbour modes, with a Rule Editor that explains itself: a live result preview per rule, coverage reporting, Add Missing, and Sort by Pattern.
- Stamps that carry exact tiles — a multi-cell prop is one named stamp; each cell can name its own tile-set tile instead of resolving through the rule set on every placement.
- Parallax from depth, not scrolling — tile layers sit at their
ZOffset, backgrounds at their own authoredDepth, and a perspective camera turns depth into parallax; nothing scrolls by default, and the asset editor previews the same authoring pose the runtime uses. - Per-tile collision shapes — Full Cell, the Paper2D tile set's own authored shapes, or a fallback between the two; solid and one-way tiles partition before meshing so a mixed run never fuses into one box.
- Native Box2D 2D physics — bodies, joints, movement, and queries backed by a vendored Box2D 3.2 (double-precision) static library, with a dedicated adapter that turns tile collision geometry into live Box2D bodies and keeps regeneration atomic.
- LDtk and Tiled JSON import/export — selected-level LDtk import, including external
.ldtklfiles, cross-checked against the real format in LDtk Format Reference below. - Shared definitions across levels — promote a level's local rule/tile definitions into a shared container, with cook partitioning so one shared container doesn't drag every other level's art into every cook.
- Optional replicated multiplayer — bounded, paged world-tile replication; authoritative Box2D puppets for co-op; and an additive client-prediction protocol layered on top. The replication types and the prediction protocol are implemented with source-level invariants and automation, documented in Documentation below; real net-driver verification (actual client/server sockets, not in-process fixtures) is still pending — see Predicted Box2D Movers: Causal Correction.
- Runtime tile editing — edit tiles at runtime with atomic Box2D collision regeneration, so a failed replacement can't leave collision half-rebuilt.
| Module | Type | Purpose |
|---|---|---|
TileMapPlus |
Runtime | The map asset, auto-tile resolution, tile animations, and physics-free collision-chain export. No Box2D dependency. |
Box2DRuntime |
Runtime | Box2D 3.2 bodies, shapes, joints, movement, and queries (BOX2DRUNTIME_API), absorbed in-tree from the standalone Box2D plugin. |
TileMapPlusBox2D |
Runtime | The adapter — turns a tile map's neutral collision geometry into live Box2D bodies. |
TileMapPlusEditor |
Editor | The asset editor (Viewport, Layers, Palette, Details, Rule Editor), the LDtk/Tiled importer, and the editor-side automation tests. |
Box2DEditor |
Editor | Box2D component visualizers and details customizations. |
Box2DLibrary (Source/ThirdParty/Box2DLibrary) is the vendored External module — the
static box2d.lib / libbox2d.a plus headers — that Box2DRuntime links privately. It is
never listed in the .uplugin's own module array.
One doc grounds LDtk interop against the real format; the rest are docs/solutions/ — one flat
file per problem, each with a measured root cause, rejected approaches, and the test that pins
the fix.
| Doc | Covers |
|---|---|
| LDtk Format Reference | Field-level reference for the LDtk project JSON format — identifiers, layers/tiles, IntGrid & auto-rules, tilesets, entities, versioning — cross-checked against the schema and real sample files. |
| Doc | Covers |
|---|---|
| Render Anchor & Parallax Reference | Why rendered tiles, collision, and parallax all read from one lattice origin and one parallax reference. |
| Parallax Render-Graph Lifecycle | One authored domain, one lifecycle-owned derived render/collision/entity graph, and generated-resource suspension. |
| Editor Interaction Foundation | The brush/gesture/undo model behind painting, selection, and World Level Edit mode. |
| Cook Partitioning & Package Graph | Selective cook partitioning so a shared definitions container doesn't drag every level's art into every cook. |
| Shared Definitions, Compatibility View & Promotion | Promoting a level's local rule/tile definitions into a shared container without breaking self-contained assets. |
| LDtk Selected-Level Import | Deterministic import of one selected LDtk world/level, including external .ldtkl files, with atomic failure. |
| Content-Demo Build/Cook/Package Proof | Why content-bearing demos need editor, cook, package, and packaged-runtime proof as separate, non-substitutable gates. |
| Runtime Collision View & Atomic Box2D Regeneration | Runtime tile edits and all-or-nothing Box2D collision regeneration. |
| TileMapPlus → Box2D Adapter Architecture | How the TileMapPlusBox2D module turns tile-map collision geometry into live Box2D bodies. |
| Slate Viewport Zoom Anchor Offset | Smooth zoom interpolation via anchor-point tracking in the 2D viewport. |
| Doc | Covers |
|---|---|
| World-Causal Tile Revisions | Joining replicated cell state to logical, render, Chaos, and Box2D geometry under one causal barrier. |
| Bounded Paged Iris Replication | Scaling tile-world replication past one FastArray with authenticated, paged Iris seals. |
| FastArray Prepared Publication | Preparing a FastArray transaction without dirtying or renumbering the live replicated property. |
| Net Commit/Callback Barrier | Publishing a prepared multi-map transaction atomically across callback-heavy UE collision APIs. |
| Net Wire Budget & Engine Sentinels | Keeping a truthful manifest inside a wire budget, and two engine enum/name sentinels that break naive checks. |
| Network Physical-Parity Probe Coordinates | Why a loss/late-join physics parity probe must use the published map geometry, not a hardcoded coordinate. |
| Network Request & Entity Boundaries | Rate-limiting edit requests, and keeping server-authoritative entity spawn from overriding actor replication policy. |
| Replication Immutable Baseline & Worldless Assets | Why the shared tile asset needs an immutable baseline and explicit worldless-asset locks. |
| Networking N0: Authority, Headless Truth & Schema Boundaries | Process-authority (not actor-authority) gating, and why dedicated servers allocate no render state. |
| N1b Authoritative Box2D Puppets | Delayed authoritative body/input streaming, possession epochs, and exactly-once cooked entity identity. |
| Predicted Box2D Movers: Causal Correction | Client-side prediction, replay, and correction across network, physics-step, and world-mutation domains. |
| UE 5.7 FastArray Receive Batches | What UE 5.7 actually calls on FastArray receipt, and draining tile edits at the physics-step boundary. |
| Doc | Covers |
|---|---|
| Box2D Audit Remediation & Pin Bump | Closing record for the Box2D audit remediation: invariants, rejected approaches, measured failure fingerprints. |
| Contact Introspection & Orientation | Asking "what is this body touching right now", receiver-relative, without reconstructing state from events. |
| Cross-Platform Determinism Closure | Canonical math, canonical creation order, and a comparable determinism artifact across Win64/Linux. |
| Event Dispatch Safety Patterns | Avoiding crashes when a collision-event handler destroys actors mid-broadcast. |
| Fixed-Tick Hook & One-Shot Input | The one pre-step hook, input latching, and apply-once one-shot APIs that make movement frame-rate independent. |
| Headless & In-Engine Testing | Driving FBox2DWorld and the full component stack in automation without a GUI. |
| Mover Landing Closure & Initial-Overlap Recovery | Depenetrating a mover spawned inside geometry without stealing its authored travel. |
| Mover Step Replay & Module FP Semantics | Why bUseUnity=false isn't a floating-point flag, and how UE 5.7 actually defaults MSVC module FP semantics. |
| Mover Toolkit PerformMovement | The simultaneous-plane character-controller solve: mutable planes, command-safe stops, honest one-way stairs. |
| Mover Wrapper & Callback-Hybrid Query | Combining identifiable overlap planes with an unidentifiable translation cast for CollideMover. |
| One-Way Platform Filtering Patterns | Why pure velocity-based PreSolve filtering is unstable at rest and at shallow angles. |
| Ordered Pre-Step Phases | Getting a causal ordering guarantee out of UE multicast delegates, without a second physics hook. |
| Production Readiness Patterns | The PIE-validation hardening pass: event semantics, movement correctness, safety guards, diagnostics, editor tooling. |
| Render Interpolation, Two-Domain History | Interpolating a transform that is simultaneously render output and a simulation input. |
| Shape Offsets Are Body-Frame | Shape-component offsets are relative to the owning actor's pose, never the attach parent. |
| Surface-Material Identity & Chain Rebuild | Versioned material identity so a chain rebuild preserves per-segment friction/restitution/conveyor data. |
| Chain-Cast Backport & Cross-Build | Backporting an upstream one-sided-chain fix and cross-compiling for Linux without faking the target. |
| Vendored-Library Version Assessment (superseded) | Historical v3.1.1-vs-upstream assessment; superseded by the 3.2.0-dev pin — kept for provenance. |
| World Tuning: Creation-Time Projection | Validating b2WorldDef fields before the destructive world-recreate path can destroy a valid world. |
| XZ_YDown Plane & Conventions | The Paper2D-aligned simulation plane and the one screen-space convention that makes every plane behave alike. |
| Feel Baseline Recordings | Why a movement-feel refactor needs a recording made before the change, not a legacy-toggle comparison. |
| Doc | Covers |
|---|---|
| Fail-Closed Automation & Mutation Testing | The house rules behind this repo's test suite — see Testing below. |
| RunUAT BuildPlugin Workflow | Building a standalone plugin with no host .uproject, via RunUAT BuildPlugin or a junction link. |
| UBA OOM Kill-Loop | Diagnosing a build that livelocks at zero completed actions on a memory- and disk-constrained machine. |
| UMovementComponent Base-Class Pitfalls | UPROPERTY shadowing and virtual-hiding traps when deriving from UMovementComponent. |
| Game-Target PCH Missing Includes | Why code compiles in the Editor target and fails in the Game target with "use of undefined type". |
| Transactional Reconcile / Probe / Friend-Link Traps | Three MSVC/linker traps from a backup-first reconcile coordinator: probes, anonymous-namespace friends, incremental links. |
| TWeakObjectPtr Blueprint Limitation | UHT rejects TWeakObjectPtr inside a BlueprintReadWrite UPROPERTY. |
| UE 5.8 Engine-Behavior Migration Traps | Four engine/environment behavior changes the first full UE 5.8 suite run surfaced, unrelated to the branch under test. |
| One Persistent UE 5.8 Host | Why the maintainers' automation runs against one reused host project instead of a disposable one per run. |
Automation tests live beside the code they cover, one .cpp per test file under each module's
Private/Tests/ folder, registered with IMPLEMENT_SIMPLE_AUTOMATION_TEST /
IMPLEMENT_COMPLEX_AUTOMATION_TEST. Test names are dotted paths that group into three prefixes:
| Prefix | Covers |
|---|---|
TileMapPlus |
143 tests: the rule engine and multi-world layout under the plain TileMapPlus.* namespace (Source/TileMapPlus/Private/Tests), plus every TileMapPlusBox2D.* adapter test the prefix also matches as a plain string (Source/TileMapPlusBox2D/Private/Tests and the legacy-replication fixtures in Source/TileMapPlusEditor/Private/Tests). |
Box2D |
243 tests: the Box2D physics plugin itself — bodies, joints, queries, movement, networking (Source/Box2DRuntime/Private/Tests, Source/Box2DEditor/Private/Tests, and Source/TileMapPlusEditor/Private/Tests/Box2DEditorLifecycleTest.cpp). |
Paper2DPlus |
521 tests under the historical Paper2DPlus.TileMapPlus.* / Paper2DPlus.Box2D.* namespaces — disjoint from the other two prefixes, retained from before the tile-map half was split out of the Paper2DPlus plugin, and still holding the bulk of the importer, asset, replication, and Box2D suites. |
All three prefixes are required for full coverage — none of them subsumes another. Run the suite
headlessly with UnrealEditor-Cmd, filtering by prefix (StartsWith: can be
chained with + to run several prefixes in one pass):
"<EngineRoot>/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "<YourProject>.uproject" ^
-ExecCmds="Automation RunTests StartsWith:TileMapPlus+StartsWith:Box2D+StartsWith:Paper2DPlus" ^
-TestExit="Automation Test Queue Empty" -unattended -nopause -nosplash -nullrhi ^
-ReportExportPath="<OutputDir>"
<OutputDir>/index.json reports the pass/fail/skip counts. scripts/run-tests.ps1 is the
maintainers' own wrapper around this same three-prefix run, built and pointed at their
persistent development host — it is not a portable entry point for a plugin consumer, but its
default -TestFilters @('Paper2DPlus', 'TileMapPlus', 'Box2D') is exactly the prefix set above.
A handful of tests are manual/opt-in rather than acceptance: Manual.AssetAuthoring.*
regenerates committed test fixtures and requires an explicit flag
(-TileMapPlusBuildCookCorpus or -TileMapPlusBuildSamples) — it is not part of an ordinary
run and will fail closed without that flag.
MIT — see LICENSE. You may use, modify, and redistribute this source, including commercially, provided the copyright notice is retained.
The vendored Box2D library is separately MIT-licensed by Erin Catto; see THIRD_PARTY_NOTICES.md for the vendored-library accounting, or its own LICENSE and NOTICE directly.
See CHANGELOG.md for release history.
- Issues: https://github.com/Infinitegameworks/TileMapPlus/issues
- https://github.com/Infinitegameworks
Built by Infinite Gameworks.