Levels

1. Level file (level.xml)

Below is a sample level.xml content, with links to documentation for every attribute.

  • (Almost) every attribute is optional, so in practice there's no need to specify them all in your level.xml files.
  • See manual chapter "Loading game level" for information how to initialize levels from such files.
<?xml version="1.0"?>

<level
  name="required_level_name"
  type="Level"
  scene="required_scene_file_name_or_url.x3d"
  title="Required Level Title"
  number="0"
  demo="False"
  title_hint=""
  default_played="False"
  placeholders="x3dshape"
  loading_image=""
  loading_bar_y_position="0.5"
  placeholder_reference_direction="1 0 0"
  music_sound="">

  <!--
    prepare_resources is an optional element.
    It should contain a list of resources (creatures;
    no need to list items, as they are always prepared (by default),
    see T3DResource.AlwaysPrepare) used by the level.
    Every <resource> element should refer to the resource name,
    that is you should have resource.xml file with name="TestCreature"
    in your data.
  -->

  <prepare_resources>
    <resource name="TestCreature" />
    <!-- And more <resource> elements... -->
  </prepare_resources>
</level>

2. Placeholders

A major feature of loading level through TLevel.Load is that you can put "placeholders" on your level 3D model. These are 3D shapes with special names that will be recognized by the engine:

  • Initial creatures / items are indicated by placeholders named CasRes + resource name. CasRes is short for Castle Game Engine Resource.

    The resource name refers to T3DResource.Name, it much match one of name="ResourceName" declarations in your resource.xml files.

    • To place a creature on the level, name your placeholder CasRes<resource-name>[<optional-initial-life>][_<ignored>][.<ignored>]. By default (if not explicitly specified), the initial creature life is taken from default_max_life given in resource.xml. It is possible to place a creature corpse on the level this way, by specifying life as 0. Initial creature looking direction is determined by the transformation of the placeholder object, see PlaceholderReferenceDirection, in short: look at where local +X of the placeholder is pointing.
    • To place an item on the level, name your placeholder CasRes<resource-name>[<optional-item-quantity>][_<ignored>]. By default (if not explicitly specified), item quantity is 1.

    Anything after underscore or dot is ignored. So e.g. CasRedMedKit.123 is understood to include resource named MedKit.

  • Water volume by placeholder "CasWater" (see TLevel.Water).

  • Move limit by placeholder "CasMoveLimit" (see TLevel.MoveLimit).

  • Sectors / waypoints to improve creature AI moving. Each sector occupies some volume in 3D (like a room). Each waypoint indicates a point to pass when moving from one sector to another (like a narrow door between two rooms). Sectors create a graph, with waypoints indicating the graph connections. If the creature is in a different sector then it's target, it walks through appropriate waypoints.

    Placeholders named CasSector<index>[_<ignored>] define sectors. Placeholders named CasWaypoint[_<ignored>] define waypoints.

    Sectors of waypoints (and reverse property, waypoints of sectors) are automatically calculated, by looking how waypoints bounding boxes collide with sectors. This is the only moment when waypoints bounding volumes are considered, for all other purposes waypoints are simply 3D points. You should place boxes that indicate waypoints between two neighboring sectors, such that the bounding box of the waypoint is partially inside both sectors.

    Sectors boxes need not be strictly separated. When 3D object, like player or a creature, is within two sectors, it's arbitrarily assigned to any of the possible sectors. However, for creature AI, this may cause some awkward movement (when the creature goes to a waypoint, instead of directly to the target), so try to set sectors that don't overlap (much).

    You don't have to cover whole level with sectors. If a creature (or it's target) is not inside any sector, then the move direction is simply set to go to the target directly.

  • See TLevel.Load documentation for full list of placeholders.

  • And possibly your TLevelLogic will define even more placeholders (by overriding TLevelLogic.Placeholder, and using your logic as LogicClass.

The "placeholders" attribute in level.xml determines how we derive "placeholder name" from a VRML/X3D shape.

  1. "x3dshape" (default) means that the placeholder name comes from VRML 2.0/X3D Shape node name (set using "DEF" in VRML/X3D).
  2. "blender" means that the placeholder name is detected following standard Blender -> glTF and Blender -> X3D exporters behavior. This allows you to set the placeholder name easily in Blender. In case of exporting to glTF, just set the Blender mesh name. In case of exporting to X3D, just set the Blender object name.
  3. and possibly more, see PlaceholderNames list and TPlaceholderName docs. You can define and register your own functions there, to handle other 3D modelers, like 3ds Max or Maya or anything else (and you're welcome to contribute them to include them in engine code, of course!).