Skip to main content

levels

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.

Jump to install

Source facts

Repository
vchelaru/FlatRedBall2
Last source activity
August 25, 2026 at 20:57
Detected SKILL.md language
English
Stars
14
Forks
6

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
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: ```csharp 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); // center map on world origin 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: ```csharp map.GetLayer("Foreground").Z = 100f; ``` ## Multiple Collision Types ```csharp 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: ```csharp 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 `AARect`s, 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: ```csharp 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. Pick one method per Class. If a Class must feed both, call `CreateEntities` **first**: it consumes what it matches (clears the tile, removes the object), while `GenerateCollisionFromClass` consumes nothing — so collision-first builds the shape before the removal and you get a shape *and* an entity. Place tile objects on Tiled object layers (using tiles with a Class set in the tileset). Game code spawns entities from them with `CreateEntities`: ```csharp // Coins — center origin (default) map.CreateEntities("Coin", _coinFactory); // Player — feet at bottom of tile var player = map.CreateEntities("PlayerSpawn", _playerFactory, Origin.BottomCenter)[0]; // Ceiling turret — top of tile 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`: ```csharp cam.Map = map.Bounds; ``` ## Map Dimensions ```csharp map.Width // total width in world units map.Height // total height in world units map.TileWidth // single tile width map.TileHeight // single tile height ``` ## 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: ```csharp MoveToScreen<Room2Screen>(s => s.RoomState = _sharedState); ``` ## Level Advancement Pass the next level index when transitioning screens: ```csharp if (levelComplete) { int next = LevelIndex + 1; if (next < TotalLevels) MoveToScreen<GameScreen>(s => s.LevelIndex = next); else MoveToScreen<GameOverScreen>(s => s.Win = true); } ```
View on GitHub