| name | levels |
| description | Level Data in FlatRedBall2. Use when working with level layouts, level progression, loading TMX maps, generating collision from tile layers, or transitioning between levels. Covers TMX-based level setup, TileShapes generation, and level advancement patterns. |
Level Data in FlatRedBall2
Levels are defined as TMX files using the Tiled map format. Use the tmx skill to create or edit TMX files.
Level Setup in a Screen
Load a TMX file with TileMap, add it to the screen, and generate collision:
using FlatRedBall2.Tiled;
public class GameScreen : Screen
{
private TileShapes _solidCollision = null!;
public override void CustomInitialize()
{
var map = new TileMap("Content/Tiled/Level1.tmx", Engine.GraphicsDevice);
map.CenterOn(0, 0);
Add(map);
_solidCollision = map.GenerateCollisionFromClass("SolidCollision");
Add(_solidCollision);
}
}
Key types (all in FlatRedBall2.Tiled):
TileMap — loads a TMX file, wraps layers, generates collision
TileMapLayer — per-layer Z, visibility, and render layer control
TileShapes — collision grid (FlatRedBall2.Collision)
TileMap Position
TileMap.X and TileMap.Y define the top-left corner of the map (Tiled convention). Default (0, 0) places the top-left at the world origin; the map extends right (+X) and down (−Y).
CenterOn(worldX, worldY) repositions the map so its center is at the given point.
Layer Z-Order
Layers are assigned Z values automatically: 1 apart in TMX order, with GameplayLayer at Z = 0 if it exists. Entities at Z = 0 naturally interleave at the gameplay layer. Override per-layer Z only when needed:
map.GetLayer("Foreground").Z = 100f;
Multiple Collision Types
var solid = map.GenerateCollisionFromClass("SolidCollision");
var jumpThrough = map.GenerateCollisionFromClass("JumpThroughCollision");
Add(solid);
Add(jumpThrough);
Each collection can have its own collision relationship. For jump-through platforms, set OneWayDirection = OneWayDirection.Up and CanDropThrough = true on the relationship — the player passes through from below, lands from above, and can drop down with Down+Jump. For hard one-way barriers (OneWayCollision tile class — Yoshi-style ratchet doors), set OneWayDirection = OneWayDirection.Up and leave CanDropThrough = false. See the collision-relationships skill for details. By default all tile layers and object layers are scanned — hand-drawn rectangle/polygon <object>s with a matching Class are collision sources too, not just painted tiles (see "Collision from hand-drawn object-layer shapes" below). Passing layerName restricts the scan to a single tile layer, skipping object layers entirely:
var solid = map.GenerateCollisionFromClass("SolidCollision", layerName: "GameplayLayer");
Slope Tiles and Sub-Cell Shapes
Tiles in the tileset can declare custom collision via an <objectgroup> containing polygons and/or plain <object> rectangles. GenerateCollisionFromClass emits polygons as Polygon tiles and rectangles as sub-cell AARects, instead of the default full-cell rect. Polygons and rects can coexist on the same tile. For platformer floors, set SlopeMode = PlatformerFloor on the collision relationship (not on the collection) so vertical separation uses a heightmap instead of SAT:
var solid = map.GenerateCollisionFromClass("SolidCollision");
Add(solid);
var playerVsSolid = AddCollisionRelationship(_playerFactory, solid);
playerVsSolid.SlopeMode = SlopeCollisionMode.PlatformerFloor;
playerVsSolid.BounceFirstOnCollision(elasticity: 0f);
SlopeMode is a per-relationship concern: the same solid collection can simultaneously back a player relationship (PlatformerFloor) and a ball relationship (default Standard SAT) without conflict.
See the tmx skill for how to author the polygon on the tileset tile.
Collision from Hand-Drawn Object-Layer Shapes
For a collision boundary that doesn't match the tile grid (an irregular wall, a boss-arena floor), draw a rectangle or polygon directly on an object layer with a matching Class instead of stamping tiles — GenerateCollisionFromClass/GenerateCollisionFromProperty pick these up too. Rectangles support any position, size, and 90-degree-multiple rotation (clipped across however many cells they span); polygons and other-angle rotated rectangles must fit within roughly one cell. See the tmx skill's "Collision from an object layer" section for the full capability split and the rotation-pivot gotcha.
Spawning Entities from Object Layers or Painted Tile Layers
CreateEntities scans both object layers (for precisely-placed tile objects) and regular tile layers (for tiles painted with Tiled's brush). Any tile whose Class matches the requested name becomes one entity — use whichever authoring path fits the designer's workflow. Painted tile layers support class-level (tileset type) custom properties but not instance-level overrides — Tiled has no per-cell property mechanism for painted tiles.
The Class-name convention disambiguates intent via which method you call: GenerateCollisionFromClass("SolidCollision") turns matching tiles into static TileShapes geometry; CreateEntities("Coin", factory) turns matching tiles into factory-spawned entities. The two methods never fight over the same tile — pick one per Class.
Place tile objects on Tiled object layers (using tiles with a Class set in the tileset). Game code spawns entities from them with CreateEntities:
map.CreateEntities("Coin", _coinFactory);
var player = map.CreateEntities("PlayerSpawn", _playerFactory, Origin.BottomCenter)[0];
map.CreateEntities("CeilingTurret", _turretFactory, Origin.TopCenter);
The engine converts Tiled's pixel coordinates (Y-down) to world space (Y-up) and sets each spawned entity's X/Y to the world-space position of the tile object, adjusted by the Origin parameter.
Source tiles are removed by default. After spawning, CreateEntities clears the painted cell and removes the tile-object from its object layer so the source tile doesn't double-draw under the spawned entity. The mutation is in-memory only — the .tmx file is untouched, and a hot-reload repopulates the source tiles so the next spawn pass picks them up again. Pass removeSourceTiles: false to keep the source tile visible (e.g., the tile doubles as intentional background art). This is the opposite default from GenerateCollisionFromClass, which leaves source tiles visible because there the tile is the visual.
Custom properties set on tile objects in Tiled are automatically applied to matching entity properties via reflection. If a Coin entity has public int Worth { get; set; } and the Tiled object has a custom property Worth=50, it's set automatically. Supported types: string, int, float, bool. Class-level properties (defined once on the tile's type in the tileset) are merged in the same way; an instance-level property on the same key overrides the class-level value. Declare a TiledGid property (int, uint, long, or ulong) to have the spawning tile's Tiled GID populated automatically — opt-in only, not a member of the base Entity class.
Class matching checks the object's Class first, then falls back to the tile definition's Class in the tileset. Case-insensitive.
Sprite + collision on the spawned entity: author it as an .achx chain (single-frame is fine) rather than hand-computing offsets in CustomInitialize — see animation skill's per-frame shapes.
Camera Bounds
TileMap.Bounds returns a BoundsRectangle for CameraControllingEntity.Map:
cam.Map = map.Bounds;
Map Dimensions
map.Width
map.Height
map.TileWidth
map.TileHeight
Rooms as Separate Screens
Each distinct room or area is its own Screen subclass. There is no built-in "room manager" — MoveToScreen<T> is the room transition mechanism. Room state is passed via the configure callback:
MoveToScreen<Room2Screen>(s => s.RoomState = _sharedState);
Level Advancement
Pass the next level index when transitioning screens:
if (levelComplete)
{
int next = LevelIndex + 1;
if (next < TotalLevels)
MoveToScreen<GameScreen>(s => s.LevelIndex = next);
else
MoveToScreen<GameOverScreen>(s => s.Win = true);
}