Unrobust Animations
This is a good catch all for the many issues with the current animations system.
This thread is dedicated primarily to the engine related issues, hence the name, although it will touch on code-base level issues for examples as to where the current system fails or goes wrong.
In the future, a second thread dedicated to SS14 specific animation problems will need to be made but the vast majority of those issues can only be solved by better engine code.
As of writing, the animation code is extremely bare bones and obtusely restrictive.
Nothing is in shared so starting and stopping animations must be done entirely by the client,
the server has no way of knowing what animations are running, literally nothing is in shared.
The methods and helpers are extremely bare-bones, just simple stop, start, is this animation running, how many animations are running.
AnimationTracks are bulldozers. Although the system supports multiple tracks and animations running at once, there are seldom cases where there is benefit to this because tracks set data irregardless of what the rest of the animation or what other animations are doing, resulting in animations bulldozing each-other and themselves (if they have multiple tracks that modify the same property).
These limitations lead to copypasted code all around SS14 or worse, true coding sins being committed (as in the case of the LightBehaviorSystem).
So what can be done at least on the engine side?
Adjustment Layers
Adjustment layers are my solution to the bulldozing problem. Adjustment layers would be a type of AnimationTracks who instead of setting a property, would get a property, then set the property to the received value plus some adjustment.
This sounds simple at it is, but because it’s adjusting values it would require its own interpolation methods that are separate from regular AnimationTracks requiring a bit of math (but not too much).
The big issue comes with how it interacts with current AnimationTracks. Because current AnimationTracks set values without caring about anything else, they will need to be run first always if possible.
I’m not sure if AnimationTracks should be made obsolete as being able to define a specific value you want to a property to go to plus, regardless of everything else, is very important.
It’s possible that ability could be moved to specifically keyframes for better modularity, or to another type of AnimationTrack with defined limitations with the old tracks being marked as obsolete but I would want a comment from an engine professional on this.
Combined Layers
An alternative to adjustment layers, instead of having multiple layers and animations per component property, you combine them all into one large component property animation with predefined keyframes for every gametick using math and then just iterate though the gameticks.
I don’t believe in this idea because it has lots of problems, like needing to remake the animation anytime you add, pause, or remove an animation that adjusts that property. It would certainly work, and may it some cases be more efficient but I think the extra complexity isn’t worth it unless someone smarter than me has a good reason why it would be.
KeyFrames and AnimationTrack set permissions to public
This is actually the easiest change and also the most important. Changing this would allow simple rigid animations to be defined purely in yaml.
Not all animations, especially those with randomization, those that take inputs from many components or variables, and those that may change dynamically, would be able to be defined in yaml, but this change would benefit them to since you could feed keyframes and tracks directly into an Animation that is then fed into the AnimationSystem without any horrible workarounds.
What kind of workarounds? Take a look at what the LightBehaviorComponent has to do to. It builds an animation with 0 keyframes which is quite impressive but also might be the worst thing to ever grace this codebase.
Pause, Resume, Skip, Rewind, Restart, and Loop Animations
There needs to be more methods other than Stop and Play. Being able to Pause and Resume would be extremely helpful methods to control animations so that you could pause one animation to let another play, then resume when it’s finished.
It would also be helpful for PVS where animations restart if you leave and re-enter PVS, with skipping being useful for moving to the correct keyframe after re-entering PVS for most animations.
Looping is a behavior that would be mildly useful. You can already loop animations by just playing them again when they stop (there’s helpful events for it already) but having an in engine loop that you can disable when X happens could be more efficient in some cases.
The same goes for rewind and restart where these are useful methods to have even if their use is more limited.
Animations to Shared
Not everything needs to be moved to shared, but enough should be moved to shared that the server can tell clients to play an animation and know what animations are playing.
The server shouldn’t be simulating animations since they are entirely cosmetic but it should be able to do everything else if it needs to.
Truthfully this is the only part I feel I will need help with. I’m not super familiar with networking so I will need someone to explain to me how to make it so the server can tell the client to run code through a shared system.
Animation Constructors and YAML
Emogarbage actually gave me this idea with their engine PR. #5810
Animation Constructors would be methods that take in data and spit out an animation. Typically these would be Game-Side but very generic constructors could be very useful on the engine side (As Emo’s PR shows).
A generic one to three keyframe animation constructor with optional randomization parameters would be generic enough it would fit in the engine (unless I’m mistaken) and would act as a good example for how to construct something of the sort for a game.
In addition, they should be compatible with yaml, if the constructor is simple enough it shouldn’t be hard to make an animation by defining:
- type: animation
- id: my animation
- length: 0.25f
- repeat: false
- blacklists:
[blacklists]
- tracks:
track1:
comp: sprite
property: rotation
interpolation: linear
keyframes:
- (0, 0f)
- (1.57, 0.5f)
- (3.14, 1f)
This is a basic example of what a flips animation could look like if defined in yaml, rigid predictable animations like this shouldn’t need their own dedicated constructors written in C#.
Constructors of course shouldn’t and wouldn’t be engine only, and won’t always been yaml definable. All the data should be stored in a component somewhere but sometimes you’ll have an animation so complex it’s impossible to define in YAML.
For example, you might have a stamina animation, where Urist McHands begins breathing heavily, the frequency of the breaths being determined by his lungs, his stamina level, and maybe the atmosphere, combined with another track for his muscles spasming from the stress taking into acount other variables from other components and systems, with a bit of randomization and perhaps some other extra keyframes for flavor.
An animation such as this would need its own constructor and wouldn’t/shouldn’t be possible in engine. It’s too complex and too specific to the context of the game around it to even worry about.
These kinds of constructors would be out of scope for an engine PR but I am bringing them up to set a clear boundary scope. Most animations in game can probably be converted to YAML and use generic constructors to build them.
Dynamic Animations
This is less of a have and more of a want. But being able to redefine animation key frames while an animation is running would be extremely useful. This should in theory be possible with just the changes listed above but if I’m missing something I’ll again need a comment from someone smarter than me.
Also to note Dynamic Animations would fall under the “Make your own constructor” type of animation, pretty much entirely game code not definable in YAML.
Animations Strike Team
Animations Strike Team will be reserved for game facing stuff. I don’t believe the engine changes are large enough in scope to warrant a team. However making the animations in game use the full benefits of new engine features and dealing with hell systems like the LightBehaviorSystem as well as creating an AnimationControllerSystem, whitelists, blacklists, ect. ect. will needs its own team and its own thread.