flutter3d
Showcase Changelog 38 packages API reference

The level format

since 0.4.2 Simulation, audio and XR

A level is a document: brushes for the architecture, entities for what spawns, and a validator that reads the whole thing and says what is wrong with it before anybody plays it.

Step 1: Build a small level #

Two brushes that happen to overlap by a metre, and one entity.

// Two brushes that overlap by a metre, which nothing in this format
// forbids outright but which the validator flags as worth a look.
final level = Level(
  name: 'sample',
  brushes: <Brush>[
    Brush(centre: Vector3(0, 0, 0), size: Vector3(4, 2, 4)),
    Brush(centre: Vector3(3, 0, 0), size: Vector3(4, 2, 4)),
  ],
  entities: <EntityDef>[EntityDef(type: 'spawn', name: 'start')],
);

Step 2: Write it down and read it back #

toJson and fromJson round-trip the whole document. Every brush that went in comes back out.

final json = level.toJson();
final reread = Level.fromJson(json);

Step 3: Validate it #

LevelValidator needs an EntityRegistry so it knows which entity types this game actually has; an empty one is enough to check the geometry alone. validate returns every issue it finds rather than stopping at the first.

final validator = LevelValidator(
  registry: EntityRegistry(const <EntityKind>[]),
);
final issues = validator.validate(reread);

The overlap between the two brushes shows up as one of the issues, alongside anything the validator has to say about an entity type it does not recognise.

Step 4: Edit the level, ask the validator #

The two brushes are on the floor, the green ball is the spawn, and the red lamps below are the validator's issues, one lamp to an issue. Slide the second brush apart and back until it overlaps the first, drop the spawn point, and each change goes through the same round trip: written to JSON, read back, validated. The lamps are whatever the validator says about the document it reads, not about the picture.

// The level of the first step, with the second brush slid along by the
// slider (a negative gap is an overlap) and the spawn optional, written to
// JSON, read back and validated.
final Level level = Level(
  name: 'sample',
  brushes: <Brush>[
    Brush(centre: Vector3(0, 0, 0), size: Vector3(4, 2, 4)),
    Brush(centre: Vector3(4.0 + gap, 0, 0), size: Vector3(4, 2, 4)),
  ],
  entities: <EntityDef>[
    if (withSpawn) EntityDef(type: 'spawn', name: 'start'),
  ],
);
final Level reread = Level.fromJson(level.toJson());
final List<LevelIssue> issues = LevelValidator(
  registry: EntityRegistry(const <EntityKind>[]),
).validate(reread);