During development, we kept referring to the monster in the game as "The Shade," which gave me the impression of a lumbering humanoid made out of smoke. We didn't have any dedicated artists on the team at this point, so it was up to the tech team to find a solution to upgrade the visuals for the monster from the dev version, which was a ball with eyes.
My idea was to define the monster as a stack of polylines that could lerp between different positions to create a walking animation, then use the lines as a reference for emitting particles, creating the humanoid shape out of smoke.
My original sketches figuring out the general shape
Originally, I was building the particle rig directly into the monster behavior, but when I started to realize the scope of it, I packed it into its own separate component so we could maintain the single responsibility principle.
The ParticleRig class consists of two major parts: the body and the library.
The body is a vector of the current frames that are being used and displayed, and it handles interpolating between frames, rotating segments, and emitting particles. Each segment has the capacity to rotate at individual speeds to create the visual of the segments being individual for eachother, and make a more realistic human-like movement.
The library is a backlog of all the frames not in use, so the rig can use them later, such as when the monster goes from walking to flailing in place.
Each keyframe contains two LineBuffer objects that the rig will interpolate between for movement. For example, the "legs" keyframe has a LineBuffer for when the left leg is forward, and one for when the right leg is forward.
The RigSegments make up the actual body of the ParticleRig, and maintain a pointer to the frame that they are currently rendering. During runtime, they then interpolate between the two sides of the keyframe using an ease in-out curve for smooth movement. Each segment also handles rotating itself and emitting particles at random points along each line.
The majority of the logic for the ParticleRig is kept within the definition for the KeyFrame and RigSegment classes, which makes the class overhead easy to modify and expand.
Since the Keyframes and RigSegments contain their own implementation for serialization and display within the editor, the ParticleRig just needs to call these methods on everything in the body and library, which makes it easy to implement features for easier editing on the overhead.
Within the editor, you can easily swap out the current frames being used on the body, as well as create and modify new keyframes. You can also edit several other properties about the frame, such as the particles per line, rotation speed, animation speed, and animation amplitude.
With its current implementation, each part of the particle rig only supports two frames that are interpolated back and forth, which works great for the game that we made.
Really, though, ParticleRigs are the foundation of a skeletal animation system.
If we had animators on the team, I could have expanded the class to use any number of keyframes on a timeline, with specific interpolation curves, timings, and weights.
I could also improve the overhead logic to use more of a state machine, and switch and combine animations more dynamically and smoothly by having them crossfade between each other.
The line segments could also have been used to position and render sprites or generated meshes, which would have turned the class into a more traditional 2d animation system.