Skip to content

Animation Basics

Kreeg edited this page May 20, 2021 · 2 revisions

Animation for Weapon Systems

Animation is handled in a separate CS file, from the weapon CS, and is linked via their Class name, at the end of a weapon CS file.

Animations = ExampleAnimationClassName_Animations, // Remove the // from this line, and use the Class ID of your Animation CS file to enable.

This Class name, is listed in the Animation CS file, as Line 27 , in stock files, at the time of this writing, and is like this

private AnimationDef ExampleAnimationClassName_Animations=> new AnimationDef

Now the "_Animations", is not a required part of the name, nor does the Class have to differ from the CS file's name.

Animations, function via subpart motion, this means all your animations are based on your Model's empty\node structure, be it your elevation subparts, muzzles, custom subparts, custom empties or similar, they act as positional-anchors (reference points, Origin points), for the motion, which can be rotation, direct movement, rescaling (shrink, grow), hiding (Visually removing the part), spawning smoke, or even the heat system's visual glows.


Animation Definition Creation

"

    WeaponAnimationSets = new[]
            {
          new PartAnimationSetDef
                {
                    SubpartId = Names("SubpartName", "SubpartNameIIExample"),
                    BarrelId = "Any", //only used for firing events, use "Any" for all muzzles, muzzle triggers only this animation if not Any
                    AnimationDelays = Delays(FiringDelay : 15, ReloadingDelay: 0, OverheatedDelay: 0, TrackingDelay: 30, LockedDelay: 0, OnDelay: 60, OffDelay: 30, BurstReloadDelay: 0, OutOfAmmoDelay: 0, PreFireDelay: 0),//Delay before animation starts
                    Reverse = Events(),
					TriggerOnce = Events(Tracking, StopTracking),
                    Loop = Events(),
                    EventMoveSets = new Dictionary<PartAnimationSetDef.EventTriggers, RelMove[]>

"

This is the first part, of a basic Animation set, an block can have countless sets; Each is a set, that holds typically, the opposite motion to the first, the "On", and "Off", the "Recoil", and "Recoil Reset", usually.

Subpart Names, are what controls what Subpart (or empty), is affected the "MoveSets", which will be explained later on, in this page.

Events, will be explained shortly, but are in the "MoveSet" definition when writing.

Delays, are in Ticks, and are used to create gaps between animations, delays between firing the animation & the event trigger


These animations are activated by triggers, IE Event types.

Event Types

  •     Reloading,
    
  •     Firing,
    
  •     Tracking,
    
  •     Overheated,
    
  •     TurnOn,
    
  •     TurnOff,
    
  •     BurstReload,
    
  •     OutOfAmmo,
    
  •     PreFire,
    
  •     EmptyOnGameLoad,
    
  •     StopFiring,
    
  •     StopTracking
    

Each of these Event types, react to specific situations, your weapon or block (Armor system supports animations), encounters.

A popular application of animations, is in Barrel Recoil, this uses the "Firing" Event, to track when the gun has fired, and "StopFiring" for when it has finished firing, to trigger the inverse motion.

Now a common mistake, is not realizing these Events can happen repeatedly in session, if not told to only be tracked-once.

TriggerOnce = Events(Tracking, StopTracking), This line, added inside your definition, sets which Events, are to only trigger once, preventing say, multiple instances from stacking their motions, displacing your parts.

Events, are used in the Header of an MoveSet, and are what set-off \ Activate said MoveSet


Animation: MoveSet

EventMoveSets = new Dictionary<PartAnimationSetDef.EventTriggers, RelMove[]> This is the Start of the MoveSet Area, do not delete or modify this line.

"

 [Tracking] = new[] //Firing, Reloading, etc, see Possible Events,  define a new[] for each
                            {
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    EmissiveName = "", //EmissiveName: from above Emissives definitions, TurnOn TurnOff
                                    TicksToMove = 60, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Linear,
                                   LinearPoints = new[]
                                    {
                                        Transformation(0, 2f, 0), //linear movement
                                    },
                                    Rotation = Transformation(0, 0, 0), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees, rotation is around CenterEmpty
                                },
                            },

"

This is, an Motion or Movement based MoveSet, it moves the Subpart in meters, when activated; It is in Meters, XYZ Axis Directions.

This one is controlled by the "Tracking" Event, which means once the Turret has a target, this Animation begins. It moves, the Subpart Upwards (X, Y, Z) by 2 meters.

"

[StopTracking] = new[] //Firing, Reloading, etc, see Possible Events,  define a new[] for each
                            {
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    EmissiveName = "", //EmissiveName: from above Emissives definitions, TurnOn TurnOff
                                    TicksToMove = 60, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Linear,
                                    LinearPoints = new[]
                                    {
                                        Transformation(0, -2f, 0), //linear movement
                                    },
                                    Rotation = Transformation(0, 0, 0), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees, rotation is around CenterEmpty
                                },
                            },

"

This is the Opposite, these two MoveSet Entries, are one after the other, or in secession. This is not required, for them to work, but for simplicity of organization, they are in the same AnimationSet, as they have the same subpart.

This version, moves the subpart down by 2 meters, once the Turret stops targeting; The AnimationDefinition has "TriggerOnce", so this animation will only play once; This means if a Turret tracks & loses target quickly, and repeatedly, this animation does not play multiple times, ensuring it only moves down by 2 meters, at max.

Without the "TriggerOnce", this animation in such a situation, could move the subpart downwards by an increasing distance, which will displace the part, as there is no positional-reset line, to return the part to the Intended start position. Not all animations need a trigger-once, such as barrel-spinners, but it is something you need to consider.

"

     EventMoveSets = new Dictionary<PartAnimationSetDef.EventTriggers, RelMove[]>
                    {
                        [Firing] = new[] //Firing, Reloading, etc, see Possible Events,  define a new[] for each
                            {
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    EmissiveName = "", //EmissiveName: from above Emissives definitions, TurnOn TurnOff
                                    TicksToMove = 5, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Linear,
                                    LinearPoints = new XYZ[0],
                                    Rotation = Transformation(0, 0,  300f), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees, rotation is around CenterEmpty
                                },
                            },
                        [StopFiring] = new[] //Firing, Reloading, etc, see Possible Events,  define a new[] for each
                            {
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    EmissiveName = "", //EmissiveName: from above Emissives definitions, TurnOn TurnOff
                                    TicksToMove = 1, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Linear,
                                    LinearPoints = new XYZ[0],
                                    Rotation = Transformation(0, 0, 0f), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees, rotation is around CenterEmpty
                                },
                            },

"

This is a Rotation Version, of a MoveSet Pair, as the Controls, differ, from Linear Motion.

These controls are in Degrees, and are based on XYZ Axis Rotations "RotAroundCenter" allows you to change the center point of Pivot, IE where the rotation is centered'

This set, happens to be using "Firing", and "StopFiring", Events, this set does not have "TriggerOnce" in the Header, meaning it keep repeating the Fire Motion, in sequence, so the barrel will spin 300 degrees every trigger pull, and will not do it evenly, so the barrel will not end in the same position as it started.

The "StopFiring" event, is on an "0" Degree rotation, to stop the rotation, use a negative, to reverse the direction of spin, which can be useful, in resetting the position, instead of just stopping the spin where-ever it was currently at.

"

     [Firing] =
                            new[] //Firing, Reloading, Overheated, Tracking, On, Off, BurstReload, OutOfAmmo, PreFire define a new[] for each
                            {
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    TicksToMove = 1, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Hide,
                                    LinearPoints = new[]
                                    {
                                        Transformation(0, 0, 0), //linear movement
                                    },
                                    Rotation = Transformation(0, 0, 0), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees
                                },


                            },
                        [Reloading] =
                            new[] //Firing, Reloading, Overheated, Tracking, Locked, OnOff define a new[] for each
                            {
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    TicksToMove = 1180, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Delay,
                                    LinearPoints = new[]
                                    {
                                        Transformation(0, 0, 0), //linear movement
                                    },
                                    Rotation = Transformation(0, 0, 0), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees
                                },
                                new RelMove
                                {
                                    CenterEmpty = "",
                                    TicksToMove = 1, //number of ticks to complete motion, 60 = 1 second
                                    MovementType = Show,
                                    LinearPoints = new[]
                                    {
                                        Transformation(0, 0, 0), //linear movement
                                    },
                                    Rotation = Transformation(0, 0, 0), //degrees
                                    RotAroundCenter = Transformation(0, 0, 0), //degrees
                                },
                                
                            },

"

This is an Hide\Show Type, that removes the visual subpart that it is aimed at.

This is most commonly used, for Missiles, being launched, Ammunition Belts, or similar parts that eject, break, or are discarded from the Model, in an animation.

The TickstoMove, in this case, is the speed of the concealment.

"

[EmptyOnGameLoad] = new[] //Firing, Reloading, Overheated, Tracking, On, Off, BurstReload, OutOfAmmo, PreFire, EmptyOnGameLoad define a new[] for each
                        {
                            new RelMove
                            {
                                CenterEmpty = "",
                                TicksToMove = 1, //number of ticks to complete motion, 60 = 1 second
                                MovementType = Hide,
                                LinearPoints = new[]
                                {
                                    Transformation(0, 0, 0), //linear movement
                                },
                                Rotation = Transformation(0, 0, 0), //degrees
                                RotAroundCenter = Transformation(0, 0, 0), //degrees
                            },


                        },

"

This is an Game-Load Event type.

This is commonly used, in this set, without an matching pair, to hide subparts (or do an motion, rotation, etc), when the Weapon is empty, on WorldLoad.

This is what the Event refers to, as "EmptyOnGameLoad", this is an event, that if a weapon is dry, or needing to reload, this event triggers whatever is attached to it, It is commonly used, on Missiles, to hide the spent shots, preventing a visual glitch, should the weapon be mid-reload, when the world was first-loaded.


Animations, can also include, Emissive manipulation, and Particle Generation.

However, at this time, I don't have enough examples, to explain that here.

Clone this wiki locally