Index

Sprites

Trial includes direct support for both displaying and importing animated sprites. At the base there is a sprite-entity, which displays a single sprite frame. The sprite requires a texture and a vertex-array that is created from an array of sprite-frames via make-sprite-frame-mesh.

This data can be automatically generated from a json file via the sprite-data asset. The json format should be structured as follows:

{
  "frames": [
    {
      // Position and size of the frame within the atlas. Bottom left oriented, Y-down
      "frame": { "x": 0, "y": 0, "w": 1, "h": 1 },
      // Size and offset of the frame within its padding. Bottom left oriented, Y-down
      "spriteSourceSize": { "x": 0, "y": 0, "w": 1, "h": 1 },
      // Total size of the frame including padding
      "sourceSize": { "w": 50, "h": 50 },
      // How long the frame should last, in milliseconds
      "duration": 500
    },
  ],
  "meta": {
    // Relative path to the sprite atlas
    "image": "critter-baba.png",
    // Size of the atlas image
    "size": { "w": 50, "h": 50 },
    // Array of animation clips
    "frameTags": [
      {
        "name": "Idle",
        // Starting frame, 1-indexed
        "from": 1,
        // Ending frame (inclusive upper bound)
        "to": 17,
        // Animation to play after this one, if any
        "next": "Idle",
        // Which frame to loop to
        "loop": 1
      }
    ]
  }
}

This format (except for the extra fields next and loop in the frameTags) is also supported by Aseprite and emitted by it if you export a packed sheet. You can even do so from the command line as follows:

aseprite -b --sheet-pack --trim --shape-padding 1 --sheet my-sprite.png --format json-array --filename-format "{tagframe} {tag}" --list-tags --data my-sprite.json my-sprite.ase

When you load a json file with the sprite-data asset, the asset will expose two resources: the texture of the packed atlas, and the vertex-array with the encoded frame data. However, it will also hold two arrays, the animations and the frames with the required metadata for each frame and animation clip.

You can pass the sprite-data instance as an initarg to an animated-sprite, which will cause it to properly load in all the desired data. After loading, you can start an animation on the entity with play. Animations can be named by either their index within the list of animations, or by their name (converted to a symbol). When loading a sprite-data the name is interned into the current *package*, so it is recommended to bind *package* to your game's local package in your launch function.

The animated-sprite will automatically loop the animation if its next-animation points to itself, or switch to another animation if it does not. You can also configure what frame it loops back to with loop-to. Aside from this the animated-sprite also allows controlling playback with playback-speed and playback-direction. The latter should be +1 for forward playback and -1 for backwards playback.

Please note that the animated-sprite handles the playback within the primary handle method for tick. If you add your own handlers to a subclass, you should thus either call-next-method or only use :after or :before qualified handlers for tick.

Sometimes it can be useful to react when the animation is automatically switched. When this happens, Trial calls switch-animation, on which you can install additional methods to either prevent the switch or perform other actions.

Thus, getting sprites working should be as simple as:

(define-asset (workbench sprite) sprite-data
    #p"my-sprite.json")

(make-instance 'animated-sprite :sprite-data (asset 'workbench 'sprite))

And then just using play to play whatever animation you like. By default it should start out with whatever animation is first in the asset's animation list.

Note also that the sprite asset is referred to here with asset and not //. This is because sprites need additional metadata to function properly which is not otherwise present on a general resource provided by //.