-
-
Notifications
You must be signed in to change notification settings - Fork 2
GTS Files
A .gts file is a Gondwana Tilesheet definition. It stores the information Gondwana needs to reconstruct a Tilesheet: the image source, regions, frame geometry, rendering metadata, and collision metadata.
The image pixels are normally stored somewhere else. A .gts file points to a loose image file or to an image entry inside an AssetsFile.
A
.gtsfile is a recipe, not the cake. It describes how to rebuild a tilesheet; it is not ordinarily an image container.
- The serialization model
- What a .gts definition stores
- A small example
- Loading a loose .gts file
- Image sources
- Loose and packed combinations
- Provenance
- Saving runtime tilesheets
- Bitmap and stream-backed tilesheets
- Collision inheritance
- EngineState and .gts files
- Common mistakes
Gondwana keeps the runtime object and the serialized definition separate:
GTS JSON → TilesheetDefinition → runtime Tilesheet
| Layer | Responsibility |
|---|---|
.gts JSON |
Portable, human-readable serialized data. |
TilesheetDefinition and related definition types |
The in-memory data-transfer model for the file. |
TilesheetDefinitionSerializer |
Converts definitions to and from JSON, files, streams, and runtime tilesheets. |
Runtime Tilesheet
|
Owns the decoded bitmap, regions, frame slices, and live rendering resources. |
TilesheetRegistry |
Registers live tilesheets by name. |
This separation is deliberate. Runtime classes do not need to become JSON-shaped, and tools can inspect or edit a definition without first creating every SkiaSharp resource.
The root TilesheetDefinition contains:
| Property | Purpose |
|---|---|
Name |
The logical tilesheet name used when the runtime object is created. |
Image |
A loose image path or an AssetsFile image reference. |
Regions |
The source areas, grid geometry, overhang, and collision metadata. |
Mask |
Optional RGBA color-key mask and tolerance. |
PremultiplyAlpha |
Whether the source image should be premultiplied when loaded. |
Source |
Provenance describing where the definition itself came from. |
Each TilesheetRegionDefinition stores:
NameAreaTileSizeTilePaddingRegionMarginOverhang- the region-default
CollisionAdjust - zero-based frame coordinates and optional frame collision overrides
For an explanation of the geometry properties, see Tilesheets.
A .gts file does not normally contain:
- encoded image bytes
- cached
SKBitmaporSKImageframe slices - registry or object references
- scene tiles, sprites, or animation state
- runtime disposal state
- the tilesheet
ValueBag
Those either belong to the referenced image, are rebuilt at load time, or belong to another Gondwana subsystem.
The following is an abridged loose definition for a two-frame tilesheet. System.Drawing values are represented using their normal JSON string conversion.
{
"Name": "Terrain",
"Image": {
"FilePath": "terrain.png"
},
"Regions": [
{
"Name": "default",
"Area": "0, 0, 32, 16",
"TileSize": "16, 16",
"TilePadding": {
"Left": 0,
"Top": 0,
"Right": 0,
"Bottom": 0
},
"RegionMargin": {
"Left": 0,
"Top": 0,
"Right": 0,
"Bottom": 0
},
"Overhang": {
"Left": 0,
"Top": 0,
"Right": 0,
"Bottom": 0
},
"CollisionAdjust": {
"Top": 1,
"Bottom": 1,
"Left": 2,
"Right": 2
},
"Frames": [
{
"XTile": 0,
"YTile": 0
},
{
"XTile": 1,
"YTile": 0,
"CollisionAdjust": {
"Top": 3,
"Bottom": 1,
"Left": 1,
"Right": 1
}
}
]
}
],
"PremultiplyAlpha": false,
"Source": {
"Kind": 0
}
}The first frame inherits the region collision adjustment because its own CollisionAdjust is absent. The second frame has an explicit override.
The serializer writes indented JSON, omits null values, includes default values, and ignores unknown properties while reading. Missing frame collections are normalized to empty collections. Together, those rules keep older and additive tool-authored files reasonably tolerant.
For normal game code, load through TilesheetRegistry:
using Gondwana.Drawing;
using Gondwana.Drawing.Tilesheets;
Tilesheet terrain = TilesheetRegistry.Instance.LoadFromDefinitionFile(
"Content/Tilesheets/terrain.gts");
Frame grass = terrain[0, 0];This reads the JSON, resolves the image source, rebuilds the regions and frame slices, applies mask or alpha processing, and registers the resulting tilesheet by its definition Name.
If a tool only needs the definition model, it can stop before creating the runtime tilesheet:
using Gondwana.Drawing.Tilesheets.GTS;
TilesheetDefinition definition = TilesheetDefinitionSerializer.Load(
"Content/Tilesheets/terrain.gts");
foreach (TilesheetRegionDefinition region in definition.Regions)
{
Console.WriteLine($"{region.Name}: {region.TileSize}");
}TilesheetImageDefinition supports two mutually-exclusive forms.
"Image": {
"FilePath": "images/terrain.png"
}A relative FilePath is resolved from the definition's base directory. For a loose .gts file, that is the directory containing the .gts file.
"Image": {
"AssetsFilePath": "../assets/game.gaf",
"AssetEntryName": "images/terrain.png"
}AssetsFilePath locates the .gaf; AssetEntryName locates the image within it. A relative assets-file path is resolved from the same base directory as a relative loose image path.
When the .gts definition is itself packed in the same AssetsFile as its image, the image can use only the entry name:
"Image": {
"AssetEntryName": "images/terrain.png"
}The containing AssetsFile becomes the default assets file during loading.
These source forms are intentionally strict:
-
FilePathcannot be combined with either asset property. -
AssetsFilePathrequiresAssetEntryName. -
AssetEntryNamewithoutAssetsFilePathrequires a defaultAssetsFile, which is supplied when loading a packed definition.
Ambiguous or incomplete definitions throw instead of quietly choosing one source. Quiet precedence rules are where configuration bugs go to breed.
The definition's storage and the image's storage are independent. Gondwana supports all four basic combinations:
| Definition location | Image location | Image fields | Relative paths are based on |
|---|---|---|---|
Loose .gts
|
Loose image | FilePath |
The .gts directory |
Loose .gts
|
Packed image |
AssetsFilePath + AssetEntryName
|
The .gts directory |
Packed .gts
|
Loose image | FilePath |
The containing .gaf directory |
Packed .gts
|
Packed image |
AssetEntryName, or AssetsFilePath + AssetEntryName
|
The containing .gaf directory |
For the packed/packed case:
- use only
AssetEntryNamewhen the image is in the sameAssetsFileas the definition; - include
AssetsFilePathwhen the image is in a differentAssetsFile.
using Gondwana.Assets;
using Gondwana.Drawing.Tilesheets;
AssetsFile gameAssets = AssetsFile.LoadOrCreate("Content/game.gaf");
Tilesheet terrain = TilesheetRegistry.Instance.LoadFromDefinitionAsset(
gameAssets,
"tilesheets/terrain.gts");The GTS entry must be stored with AssetTypes.TilesheetDefinition. The logical runtime name still comes from TilesheetDefinition.Name; the packed entry name is only its address inside the archive.
TilesheetDefinition.Source records where the definition came from. It does not select the image source; that remains the job of TilesheetDefinition.Image.
TilesheetDefinitionSourceKind |
Meaning | Relevant fields |
|---|---|---|
None |
No origin is known yet. | None |
LooseDefinitionFile |
The definition came from a loose .gts file. |
GtsFilePath |
PackedDefinitionFile |
The definition came from a .gts entry in an AssetsFile. |
AssetsFilePath, AssetEntryName
|
Generated |
The definition was generated in memory, commonly from a runtime tilesheet or tooling. | None |
The serializer follows these rules:
-
Load(filePath)stampsLooseDefinitionFilewhen the JSON currently hasSource.None. - Loading a definition entry through
LoadFromDefinitionAssetstampsPackedDefinitionFilewith the.gafpath and entry name. -
FromTilesheet(...)creates a definition markedGenerated. -
Load(Stream)cannot infer a physical origin, so it preserves the serialized source and otherwise leaves it asNone. - Saving a
TilesheetDefinitionwhose source isNonewrites a loose-file source into the saved clone without mutating the caller's in-memory object. - An already-explicit source is preserved when saving a definition.
This makes provenance useful to editors and tooling: they can distinguish “loaded from here” from “created in memory,” even when both definitions reference the same image.
Provenance is descriptive metadata. Path resolution is still determined by the load operation's base directory and the fields under
Image.
The simplest runtime-to-GTS save is:
using Gondwana.Drawing.Tilesheets.GTS;
TilesheetDefinitionSerializer.Save(
"Content/Tilesheets/terrain.gts",
terrain);For a file-backed tilesheet, this writes the definition and normally records the image path relative to the destination .gts file. It does not copy or duplicate the existing source image.
For an AssetsFile-backed tilesheet, the definition records the assets-file path and image entry name.
Path behavior is controlled by the optional argument:
TilesheetDefinitionSerializer.Save(
"Content/Tilesheets/terrain.gts",
terrain,
makePathsRelative: false);makePathsRelative defaults to true for Save(filePath, tilesheet). Stored path separators are normalized to /, which keeps generated JSON stable across Windows and Unix-like systems.
You can also convert without immediately writing a file:
TilesheetDefinition definition =
TilesheetDefinitionSerializer.FromTilesheet(terrain);
string json = TilesheetDefinitionSerializer.ToJson(definition);Or serialize a runtime tilesheet relative to a chosen directory:
string json = TilesheetDefinitionSerializer.ToJson(
terrain,
baseDirectory: "Content/Tilesheets",
makePathsRelative: true);Unlike Save(filePath, tilesheet), these conversion methods have no destination filename from which to choose a companion image path. A runtime-only bitmap or stream must therefore be persisted first.
A tilesheet loaded from an SKBitmap or image stream initially has decoded pixels but no persistent image address:
Tilesheet generated = TilesheetRegistry.Instance.LoadFromBitmap(
"generated-terrain",
bitmap);There are two ways to make it serializable.
TilesheetDefinitionSerializer.Save(
"Content/Tilesheets/generated-terrain.gts",
generated);Because generated has neither ImageFilePath nor AssetIdentifier, Save automatically creates:
Content/Tilesheets/generated-terrain.gts
Content/Tilesheets/generated-terrain.png
The PNG uses the same base filename, the GTS records generated-terrain.png, and the runtime tilesheet is promoted to file-backed by setting its ImageFilePath.
generated.PersistImageToFile(
"Content/Images/generated-terrain.png");
TilesheetDefinition definition =
TilesheetDefinitionSerializer.FromTilesheet(generated);PersistImageToFile defaults to PNG at quality 100, creates missing directories, records the full image path on the tilesheet, and clears any previous AssetIdentifier.
If masking or premultiplication has transformed the runtime bitmap, Gondwana persists the retained original source bitmap. The GTS mask or premultiplication metadata is then reapplied once during loading. Saving the already-transformed bitmap would apply the operation twice and slowly turn correctness into modern art.
GTS preserves the difference between these two states:
- a frame inherits its region's
CollisionAdjust; - a frame has an explicit override whose current value happens to equal the region default.
The distinction is represented by nullable frame metadata:
public CollisionAdjust? CollisionAdjust { get; set; }| Frame JSON | Meaning after load |
|---|---|
CollisionAdjust absent |
Inherit TilesheetRegionDefinition.CollisionAdjust. |
CollisionAdjust present |
Create an explicit frame override. |
The runtime serializer writes every valid frame coordinate. Inherited frames omit the nullable adjustment; overridden frames include it. Therefore, changing the region default after loading updates only inheriting frames.
Older .gts files without Frames or collision metadata remain valid. Missing collections are treated as empty, and missing collision values use their zero-value defaults.
EngineState can persist tilesheet definitions in either of two ways:
- inline inside the engine-state JSON, which is the default;
- as separate
.gtsfiles whenseparateGtsFiles: true.
using Gondwana;
Engine.Instance.State.SaveToFile(
"Saves/session.json",
separateGtsFiles: true);Separate definitions are written beneath a sibling directory named after the state file:
Saves/session.json
Saves/session.tilesheets/terrain.gts
Saves/session.tilesheets/actors.gts
The engine-state file stores relative references to those definitions when possible. Each standalone file is written with TilesheetDefinitionSerializer, not the general EngineState JSON settings, so the .gts remains clean and independently usable by the engine, tools, source control, and editors.
| Symptom | Likely cause |
|---|---|
The .gts exists but the tilesheet will not load |
The referenced loose image, .gaf, or asset entry is missing. |
| A relative image path resolves from the process directory | A definition was loaded from a stream or object without supplying the intended base directory. |
| The image source is reported as ambiguous |
FilePath was combined with asset source properties. Choose one form. |
| An entry-only image reference fails | The definition was not loaded from a containing AssetsFile, so no default assets file exists. |
FromTilesheet throws for a bitmap-backed sheet |
Use Save(filePath, tilesheet) for automatic sibling persistence, or call PersistImageToFile first. |
| A frame stops following region collision changes | Its GTS frame entry contains an explicit CollisionAdjust; clear the runtime override before saving if inheritance is intended. |
Moving a loose .gts breaks its image path |
Move its relative loose image with it, or update the image reference. |
| The runtime name differs from the packed entry name | Expected: TilesheetDefinition.Name is the logical name; the asset entry is only storage addressing. |
| Paths look different on Windows after serialization | Generated GTS paths deliberately use / for cross-platform stability. |
- A
.gtsfile stores tilesheet metadata, not image bytes. - The definition and its image can each be loose or packed independently.
- Relative paths are resolved from the loose
.gtsdirectory or the containing.gafdirectory. -
Sourcerecords definition provenance;Imageidentifies the bitmap source. -
Save(filePath, tilesheet)uses relative paths by default and automatically persists runtime-only images beside the.gts. - Region collision defaults and explicit per-frame overrides round-trip as distinct states.
- Load through
TilesheetRegistrywhen you want a registered runtime tilesheet; load throughTilesheetDefinitionSerializerwhen a tool only needs the definition.
That is the complete practical model: the .gts says what the tilesheet is, provenance says where that definition came from, and the image reference says where its pixels live.
- Home
- Make Your First Game in 30 Minutes
- Engine Architecture Overview
- Gondwana Engine Lifecycle
- Gondwana CLI Cheatsheet
- Assets Files
- Tilesheets
- Scenes and SceneLayers
- Sprites
- Views, Cameras, and Viewports
- DirectDrawing
- Game State Files
- Logging
- Movement and Controllers
- Input Handling
- Collision Detection
- Timers and Engine Timing
- Using the Effects System
- Engine Configuration