5. Resources (creatures and items)

1. Resource file (resource.xml)

resource.xml files define the properties of resources: creatures and items. Below is a sample resource.xml file, 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 resource.xml files.
  • Note that sample below shows properties for resource of type WalkAttack (indicating TWalkAttackCreatureResource class), there are other resource types (for creatures and items) with a little different properties.
  • See tutorial about resources for information how to initialize resources (creatures and items) from such files.
<?xml version="1.0"?>

<resource
  name="RequiredCreatureName"
  type="WalkAttack"
  knockback_speed="1.0"
  knockback_distance="4.0"
  flying="False"
  sound_die_tied_to_creature="True"
  default_max_life="100.0"
  radius="0.0"
  middle_height="0.5"
  sound_sudden_pain=""
  sound_die=""
  move_speed="1.0"
  min_life_loss_to_hurt="0.0"
  chance_to_hurt="1.0"
  max_height_acceptable_to_fall="1.5"
  random_walk_distance="10.0"
  remove_dead="False"
  preferred_distance="2.0"
  smell_distance="0.0"
  always_prepared="False"
  fall_speed="10.0"
  grow_speed="5.0"
  receive_shadow_volumes="True"
  cast_shadow_volumes="True">

  <!-- See lower on this page for explanation how to export animations
       and define <model> element. Below we only show all possible attributes,
       in practice you will not want to set them all. -->
  <model url="main.x3d">
    <idle         url="idle.x3d"         time_sensor="TimeSensorIdle" />
    <idle_to_walk url="idle_to_walk.x3d" time_sensor="TimeSensorIdleToWalk" />
    <walk         url="walk.x3d"         time_sensor="TimeSensorWalk" />
    <fire_missile url="fire_missile.x3d" time_sensor="TimeSensorFireMissile" />
    <attack       url="attack.x3d"       time_sensor="TimeSensorAttack" />
    <die          url="die.x3d"          time_sensor="TimeSensorDie" />
    <die_back     url="die_back.x3d"     time_sensor="TimeSensorDieBack" />
    <hurt         url="hurt.x3d"         time_sensor="TimeSensorHurt" />
  </model>

  <attack
    knockback_distance="0.0"
    time="0.0"
    max_distance="2.0"
    max_angle="0.523598776"
    min_delay="2.0"
    sound_hit=""
    sound_start="" >
    <damage
      const="0.0"
      random="0.0" />
  </attack>

  <fire_missile
    time="0.0"
    max_distance="30.0"
    max_angle="0.523598776"
    min_delay="2.0"
    sound=""
    name=""
    height="0.5" />

  <fall>
    <sound
      min_height="1.0"
      name="creature_fall" />
    <damage
      min_height="5.0"
      scale_min="0.8"
      scale_max="1.2" />
  </fall>

  <run_away
    life="0.3"
    distance="10.0" />

  <visibility
    angle="2.094395102" />
</resource>

2. Resource type

The type attribute determines the exact class (ObjectPascal implementation) used to instantiate this resource. You can use the same type many types of course, for example you can define many creatures of type WalkAttack or Missile and many items of type Item.

This type determines the behavior that is coded in ObjectPascal — like creature artificial intelligence, whether item can be equipped, what happens when item is used and so on.

The type also determines available attributes and animations of this resource. For example, only creature type WalkAttack (or it's descendants) have the <attack> animation. See the properties of resource classes to know what is available:

3. Orientation of resource 3D model above the ground

Resources models (creatures, items and such) should be modeled around 0,0,0 point. In case of resources using gravity (items and non-flying creatures), they will be placed on the ground relative to the 0 level of their model. In other words, if you want your model to float slightly above the ground, you can just move it higher above the 0 level. If the model is slightly below 0 level, it will sink into the ground. This is usually the most comfortable approach.

For flying resources (not using gravity), this doesn't matter, basically you can place 0,0,0 wherever you like. See T3DCustomTransform.MiddleHeight for precise details.

4. Animations of resources

3D resources, like creatures and items, display various 3D animations. Depending on the creature state, like standing / attacking / dying, we may want to display different animation of the given creature instance. We define these animations using the <model> element of creature/item resource.xml file.

As a developer, you can also create T3DResourceAnimation instance adding it to a T3DResource descendant, this way you can add new animations for your own/extended resources. At this point, I highly advice you compile and run the examples/resource_animations example program from the engine sources. The data/ subdirectory of it shows examples of how you can define <model>, discussed below. It is also a great program to test your own creatures/items animations (before using in the actual game), you can load their resource.xml using the "Add resource..." button and directly play loaded animations.

There are three approaches to indicate animations in <model> element in resource.xml file. Which one to choose depends on what 3D modeler / exporter you use to design your models:

  1. The best way (best for memory and loading time, which is really important in these situations) is to use a single X3D model, with many X3D TimeSensors representing different animations. You declare it in resource.xml file like this:

    <model url="model.x3d">
      <stand time_sensor="TimeSensorStand"/>
      <walk time_sensor="TimeSensorWalk"/>
    </model>

    This is nice if your 3D modeler / exporter can record multiple animations inside a single X3D file, and each animation is controlled by a different X3D TimeSensor node. This is the most natural way to record multiple animations in a single X3D file. We will detect animation length from the TimeSensor.cycleInterval, and we'll simulate sending appropriate time and fraction_changed from this TimeSensor to activate the desired moment of the desired animation.

    Unfortunately, I don't know of any open-source 3D modeler / exporter right now that can nicely produce such multiple animations in a single X3D file. I plan to extend Blender X3D exporter to allow this in the future.

  2. You can also use a separate X3D model for each animation state, like this:

    <model>
      <stand url="stand.x3d" time_sensor="MainTimeSensor"/>
      <walk url="walk.x3d" time_sensor="MainTimeSensor"/>
    </model>
  3. You can also use a precalculated animation for each animation, from KAnim or MD3 (Quake 3 engine format) file. This is useful if your 3D modeler / exporter cannot produce animated X3D files at all, but it can export to kanim (see our Blender to KAnim exporter) or MD3. In the worst case, you can also just export a couple of still frames and write the xxx.kanim file in a text editor, because the kanim format is a trivial XML file that just describes a transition between a couple of still 3D models. Internally, we'll use TCastlePrecalculatedAnimation for each animation state.

    Example:

    <model>
      <stand url="stand.kanim"/>
      <walk url="walk.kanim"/>
    </model>

    This is probably the most comfortable approach to export animations from Blender to our engine. For now — in the future we hope to extend Blender X3D exporter to store whole animation inside a single X3D file.

To describe above three cases in more precise manner for developers:

  • (Case 3. above) When animation state, like <stand> or <walk>, doesn't have a time_sensor attribute — then it must have url attribute, and we use precalculated animation, TCastlePrecalculatedAnimation, to play it. Suitable for kanim and X3D animations. Suitable also when the model is just a still 3D model, as then TCastlePrecalculatedAnimation simply renders it.

  • (Case 2. above) Otherwise, if an animation state like <stand> or <walk> has both time_sensor and url, then we load it to a TCastleScene and use appropriate TimeSensor to play the animation.

  • (Case 1. above) Otherwise, if an animation state like <stand> or <walk> has only time_sensor, then we use a 3D model defined at <model> element to choose and play appropriate animation. This also means using TCastleScene and appropriate TimeSensor to play it, but this time it's a single TCastleScene potentially shared by various animations.

In some situations, we have to know the animation duration (for example, to know when <attack> animation ends and we should get back to <stand> or <walk> state).

  • For TCastlePrecalculatedAnimation, the animation always starts from the local time 0, goes to the last time (time of last <frame> in kanim file). Then it eventually goes backward, it backwards="true" in kanim file. So we know the duration by looking at frames time and backwards property: TimeEnd + (if Backwards then TimeEnd-TimeBegin else 0).

    So using backwards="true" in KAnim works, useful for some animations when you do some gesture and then go back to original position by reversing this gesture — e.g. dog-like creature biting.

  • For TCastleScene and TimeSensor: in this case, X3D TimeSensor.cycleInterval gives us animation duration.

The looping is done automatically for animations that require it (like walk). So using loop attribute in kanim file, or loop field for TimeSensor is not necessary (it's ignored).

Design notes about X3D TimeSensor usage: All creatures of a given kind must share the same resources. E.g. imagine you have a creature type "werewolf" (defined by a resource.xml file with name="Werewolf" inside, resulting in TCastleResource instance with TCastleResource.Name="Werewolf"). You can instantiate this creature many times on the level, and all visible werewolves will actually use the same resource underneath. That is why we use TimeSensors by directly sending their time/fraction_changed, instead of just activating them by TimeSensor.startTime: in the latter case, all werewolves visible on the level would be forced to be in the same state (and moment) of the animation.