This issue is to provide an outline of possible future improvements to the updated animation extension created in microsoft/pxt-common-packages#906.
Field editors
One of the originally discussed but never implemented features is a set of field editors to ease in the process of creating both frame and movement animations.
Frame animations
The frame animations block accepts three parameters: the target sprite, an array of images to animate through, and an interval between frames. The array is prefilled with image blocks to allow easy addition of frames. This approach, while certainly usable, has several limitations:
When inserting/deleting frames, all other frames must be shifted to accommodate. This could also result in mistakes such as the accidental deletion of a frame.
Frames are not cloned from a previous frame. As many use cases for frame animations would involve only slight changes from frame to frame, it would make sense that any new frames should be a duplicate of the previous frame, ready for modification.
In addition, the editor should show the previous frame as a shadow for easy comparison.
There is no way to preview what an animation would like without playing it in the simulator as part of the game.
The recommended field editor would include the following features:
The ability to insert or delete a frame from any point in the animation, including the automatic shifting of other frames to accommodate this gracefully.
Buttons to add or delete frames.
The ability to drag to rearrange frames.
Automatic cloning of the previous frame when inserting a new frame.
A shadow view of the previous frame, visible in the embedded sprite editor.
The ability to scrub through frames and play a preview from any point in the animation.
A gallery of premade frame animations, using premade images already included in the sprite editor
A field to edit the frame interval in the editor, so that the preview rate can be changed without having to exit out of the editor.
A method of using existing images as frames. In its current state, an image can be dragged from anywhere (for instance, a sprite creation block) into the frames array, and used as a starting point for other frames.
A possible implementation might look like this:
Movement animations
The movement animation block also accepts three inputs: the target sprite, a string containing an SVG path the follow, and the total duration of the animation. At the moment, while any SVG path can technically be provided, the block instead uses a dropdown containing several premade animations. There are several limitations to this approach:
In order to create custom paths, several requirements must be met:
The user has to find and drag out a text block onto the existing dropdown to override it
The user must either be experienced with SVG path syntax or use an external SVG path editor and import the generated path.
The current method of timing is simple but can be inflexible. The input duration is divided by the number of SVG path commands to determine the interval (i.e. the duration of each SVG path command). To put it another way, in order to slow down a sprite following a straight line, it's necessary to subdivide the line into multiple line commands and multiply the total duration accordingly.
The recommended field editor would include the following features:
An area on which to draw and edit paths. The exact interface for this has not yet been planned.
Some potential options would be a simple canvas that, when drawn on, performs various smoothing optimizations and then exports a path.
A full-fledged editor with the ability to manually add each node and edit the location of each relevant point, as well as any relevant flags.
A field to enter the duration the animation should take.
A button to play the animation.
Some way to scrub through the animation.
A small icon that can move along the path to give an idea of the spreed the sprite will move at through various parts of the path.
A gallery containing premade movement animations. This could supersede the current premade animations dropdown, though support should remain for the old one.
A method of completing paths (that would use the closePath command) to return to the starting point of an animation.
We do not have a possible design for such a field editor at this point.
Elliptical Arcs
One of the few parts of the SVG path standard that is not supported is the elliptical arc command (written as A/a). This command essentially allows an arc to be taken from an ellipse and used as a path. While its behavior can in many cases be emulated with a quadratic or cubic bezier curve (which is supported), it may not be possible to do so in all scenarios. One such scenario is large arcs that might require multiple bezier curves to emulate. While the arcTo command is fairly easy to use, the implementation must be carefully planned and implemented to take into account edge cases using one of the more complicated flags. The syntax is as follows:
A radius-x radius-y x-rotation large-arc-flag sweep-flag x y OR
a radius-x radius-y x-rotation large-arc-flag sweep-flag delta-x delta-y
More details can be found here. An example use case for this command (which has been requested several times during user testing) is a vortex/tornado, where the sprite gradually moves in a circular motion towards the center of a vortex. This could be accomplished with the arcTo command like so:
M 10 10 A 1 1 0 0 1 20 10 A 1 1 0 0 1 12 10 A 1 1 0 0 1 18 10 A 1 1 0 0 1 14 10 A 1 1 0 0 1 16 10
Documentation
The newly introduced blocks do not currently have any documentation attached to them about how they can be used. This is especially problematic as there are some features (such as raw SVG path input) that do not have visibility. Any documentation for the blocks would be liable to change based on the other changes mentioned in this document.
Another issue is that the old documentation is not in a usable state. Unfortunately, several of the blocks do not correctly link to their documentation pages (the filenames are different from what the blocks reference), resulting in those pages being unreachable.
Deprecation
The intent of the new extension was to supersede the old code. However, it is known that the existing blocks are already in use, and so they should not be deprecated just yet. The use of these old blocks should be monitored, and if at a certain point there is a clear trend of moving away from the older blocks, then they can be marked as deprecated/hidden/removed.
Miscellaneous
Animation comparison
In the previous extension, activating an already running animation state would not cause the animation to restart, instead simply letting it continue. A similar behavior might be desirable for the new extension code, however it is far more complicated to implement. In order to match the behavior, a comparison between the existing animation and the new animation would need to be made, ignoring any variables such as time. Unfortunately, there is no such way to perform a comparison. While some parts of the class can be compared, such as the interval, there is no way to compare two Image objects.
Movement animation comparison is an issue that could be solved fairly gracefully already. A possible comparison method would be to have each PathNode export its corresponding SVG path syntax, which could then be concatenated at the MovementAnimation level and compared to a corresponding SVG path string.
Existing use of comparisons
The existing animation code makes use of an image comparison so that a new image will not be applied if it is the same as the current image. This functionality, migrated from the previous codebase, does not currently break any functionality, but would benefit from the ability to perform image comparison for purposes of optimization.
Closing suggestions
The below suggestions are just for consideration, and are likely not worth the time investment to implement them.
Exponents and Floats
The SVG path standard supports the use of exponents and floats in most parameters. Neither of these are currently supported, due to the fact that neither are a reasonable use case. Since rendering does not take into account partial pixels, float handling was never implemented. In addition, since the screen is only 160x120 pixels, it would not make sense for a sprite to move far enough that exponents are needed to represent their target.
With that said, there is the possibility of a user pasting in externally generated SVG paths that use these features, and this could potentially cause SVG path parsing to fail. As such, accepting them in some form could make sense. For floats, simply rounding to the closest integer, and for exponents, just parsing them into integers normally.
Nth Degree Beziers
The current SVG path implementation supports quadratic and cubic bezier curves. With that said, bezier curves can in theory have many more control points than just 1 or 2. Implementing an nth degree bezier curve command would likely require refactoring of the parser in order to accept a multitude of arguments rather than a fixed amount.
For the elliptical arc function, here are the relevant implementation notes (including the math that should be necessary to calculate a given point on the path): https://www.w3.org/TR/SVG/implnote.html
This issue is to provide an outline of possible future improvements to the updated animation extension created in microsoft/pxt-common-packages#906.
Field editors
One of the originally discussed but never implemented features is a set of field editors to ease in the process of creating both frame and movement animations.
Frame animations
The frame animations block accepts three parameters: the target sprite, an array of images to animate through, and an interval between frames. The array is prefilled with image blocks to allow easy addition of frames. This approach, while certainly usable, has several limitations:
The recommended field editor would include the following features:
A possible implementation might look like this:
Movement animations
The movement animation block also accepts three inputs: the target sprite, a string containing an SVG path the follow, and the total duration of the animation. At the moment, while any SVG path can technically be provided, the block instead uses a dropdown containing several premade animations. There are several limitations to this approach:
The recommended field editor would include the following features:
closePath
command) to return to the starting point of an animation.We do not have a possible design for such a field editor at this point.
Elliptical Arcs
One of the few parts of the SVG path standard that is not supported is the elliptical arc command (written as
A/a
). This command essentially allows an arc to be taken from an ellipse and used as a path. While its behavior can in many cases be emulated with a quadratic or cubic bezier curve (which is supported), it may not be possible to do so in all scenarios. One such scenario is large arcs that might require multiple bezier curves to emulate. While thearcTo
command is fairly easy to use, the implementation must be carefully planned and implemented to take into account edge cases using one of the more complicated flags. The syntax is as follows:A radius-x radius-y x-rotation large-arc-flag sweep-flag x y
ORa radius-x radius-y x-rotation large-arc-flag sweep-flag delta-x delta-y
More details can be found here. An example use case for this command (which has been requested several times during user testing) is a vortex/tornado, where the sprite gradually moves in a circular motion towards the center of a vortex. This could be accomplished with the
arcTo
command like so:M 10 10 A 1 1 0 0 1 20 10 A 1 1 0 0 1 12 10 A 1 1 0 0 1 18 10 A 1 1 0 0 1 14 10 A 1 1 0 0 1 16 10
Documentation
The newly introduced blocks do not currently have any documentation attached to them about how they can be used. This is especially problematic as there are some features (such as raw SVG path input) that do not have visibility. Any documentation for the blocks would be liable to change based on the other changes mentioned in this document.
Another issue is that the old documentation is not in a usable state. Unfortunately, several of the blocks do not correctly link to their documentation pages (the filenames are different from what the blocks reference), resulting in those pages being unreachable.
Deprecation
The intent of the new extension was to supersede the old code. However, it is known that the existing blocks are already in use, and so they should not be deprecated just yet. The use of these old blocks should be monitored, and if at a certain point there is a clear trend of moving away from the older blocks, then they can be marked as deprecated/hidden/removed.
Miscellaneous
Animation comparison
In the previous extension, activating an already running animation state would not cause the animation to restart, instead simply letting it continue. A similar behavior might be desirable for the new extension code, however it is far more complicated to implement. In order to match the behavior, a comparison between the existing animation and the new animation would need to be made, ignoring any variables such as time. Unfortunately, there is no such way to perform a comparison. While some parts of the class can be compared, such as the interval, there is no way to compare two Image objects.
Movement animation comparison is an issue that could be solved fairly gracefully already. A possible comparison method would be to have each PathNode export its corresponding SVG path syntax, which could then be concatenated at the MovementAnimation level and compared to a corresponding SVG path string.
Existing use of comparisons
The existing animation code makes use of an image comparison so that a new image will not be applied if it is the same as the current image. This functionality, migrated from the previous codebase, does not currently break any functionality, but would benefit from the ability to perform image comparison for purposes of optimization.
Closing suggestions
The below suggestions are just for consideration, and are likely not worth the time investment to implement them.
Exponents and Floats
The SVG path standard supports the use of exponents and floats in most parameters. Neither of these are currently supported, due to the fact that neither are a reasonable use case. Since rendering does not take into account partial pixels, float handling was never implemented. In addition, since the screen is only 160x120 pixels, it would not make sense for a sprite to move far enough that exponents are needed to represent their target.
With that said, there is the possibility of a user pasting in externally generated SVG paths that use these features, and this could potentially cause SVG path parsing to fail. As such, accepting them in some form could make sense. For floats, simply rounding to the closest integer, and for exponents, just parsing them into integers normally.
Nth Degree Beziers
The current SVG path implementation supports quadratic and cubic bezier curves. With that said, bezier curves can in theory have many more control points than just 1 or 2. Implementing an nth degree bezier curve command would likely require refactoring of the parser in order to accept a multitude of arguments rather than a fixed amount.