1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
#pragma once
#include "StarOrderedMap.hpp"
#include "StarJson.hpp"
#include "StarMatrix3.hpp"
namespace Star {
STAR_EXCEPTION(AnimatedPartSetException, StarException);
// Defines a "animated" data set constructed in such a way that it is very
// useful for doing generic animations with lots of additional animation data.
// It is made up of two concepts, "states" and "parts".
//
// States:
//
// There are N "state types" defined, which each defines a set of mutually
// exclusive states that each "state type" can be in. For example, one state
// type might be "movement", and the "movement" states might be "idle", "walk",
// and "run. Another state type might be "attack" which could have as its
// states "idle", and "melee". Each state type will have exactly one currently
// active state, so this class may, for example, be in the total state of
// "movement:idle" and "attack:melee". Each state within each state type is
// animated, so that over time the state frame increases and may loop around,
// or transition into another state so that that state type without interaction
// may go from "melee" to "idle" when the "melee" state animation is finished.
// This is defined by the individual state config in the configuration passed
// into the constructor.
//
// Parts:
//
// Each instance of this class also can have N "Parts" defined, which are
// groups of properties that "listen" to active states. Each part can "listen"
// to one or more state types, and the first matching state x state type pair
// (in order of state type priority which is specified in the config) is
// chosen, and the properties from that state type and state are merged into
// the part to produce the final active part information. Rather than having a
// single image or image set for each part, since this class is intended to be
// as generic as possible, all of this data is assumed to be queried from the
// part properties, so that things such as image data as well as other things
// like damage or collision polys can be stored along with the animation
// frames, the part state, the base part, whichever is most applicable.
class AnimatedPartSet {
public:
struct ActiveStateInformation {
String stateTypeName;
String stateName;
float timer;
unsigned frame;
float frameProgress;
JsonObject properties;
bool reverse;
unsigned nextFrame;
JsonObject nextProperties;
};
struct ActivePartInformation {
String partName;
// If a state match is found, this will be set.
Maybe<ActiveStateInformation> activeState;
JsonObject properties;
JsonObject nextProperties;
Mat3F animationAffineTransform() const;
void setAnimationAffineTransform(Mat3F const& matrix);
void setAnimationAffineTransform(Mat3F const& mat1, Mat3F const& mat2, float progress);
float xTranslationAnimation;
float yTranslationAnimation;
float xScaleAnimation;
float yScaleAnimation;
float xShearAnimation;
float yShearAnimation;
};
enum AnimationMode {
End,
Loop,
Transition
};
struct State {
unsigned frames;
float cycle;
AnimationMode animationMode;
String transitionState;
JsonObject stateProperties;
JsonObject stateFrameProperties;
};
struct StateType {
float priority;
bool enabled;
String defaultState;
JsonObject stateTypeProperties;
OrderedHashMap<String, shared_ptr<State const>> states;
ActiveStateInformation activeState;
State const* activeStatePointer;
bool activeStateDirty;
};
struct PartState {
JsonObject partStateProperties;
JsonObject partStateFrameProperties;
};
struct Part {
JsonObject partProperties;
StringMap<StringMap<PartState>> partStates;
ActivePartInformation activePart;
bool activePartDirty;
};
AnimatedPartSet();
AnimatedPartSet(Json config, uint8_t animatiorVersion);
// Returns the available state types.
StringList stateTypes() const;
// If a state type is disabled, no parts will match against it even
// if they have entries for that state type.
void setStateTypeEnabled(String const& stateTypeName, bool enabled);
void setEnabledStateTypes(StringList const& stateTypeNames);
bool stateTypeEnabled(String const& stateTypeName) const;
// Returns the available states for the given state type.
StringList states(String const& stateTypeName) const;
StringList partNames() const;
// Sets the active state for this state type. If the state is different than
// the previously set state, will start the new states animation off at the
// beginning. If alwaysStart is true, then starts the state animation off at
// the beginning even if no state change has occurred. Returns true if a
// state animation reset was done.
bool setActiveState(String const& stateTypeName, String const& stateName, bool alwaysStart = false, bool reverse = false);
// Restart this given state type's timer off at the beginning.
void restartState(String const& stateTypeName);
ActiveStateInformation const& activeState(String const& stateTypeName) const;
ActivePartInformation const& activePart(String const& partName) const;
StringMap<Part> const& constParts() const;
StringMap<Part>& parts();
// Function will be given the name of each state type, and the
// ActiveStateInformation for the active state for that state type.
void forEachActiveState(function<void(String const&, ActiveStateInformation const&)> callback) const;
// Function will be given the name of each part, and the
// ActivePartInformation for the active part.
void forEachActivePart(function<void(String const&, ActivePartInformation const&)> callback) const;
// Useful for serializing state changes. Since each set of states for a
// state type is ordered, it is possible to simply serialize and deserialize
// the state index for that state type.
size_t activeStateIndex(String const& stateTypeName) const;
bool activeStateReverse(String const& stateTypeName) const;
bool setActiveStateIndex(String const& stateTypeName, size_t stateIndex, bool alwaysStart = false, bool reverse = false);
// Animate each state type forward 'dt' time, and either change state frames
// or transition to new states, depending on the config.
void update(float dt);
// Pushes all the animations into their final state
void finishAnimations();
uint8_t version() const;
private:
static AnimationMode stringToAnimationMode(String const& string);
void freshenActiveState(StateType& stateType);
void freshenActivePart(Part& part);
OrderedHashMap<String, StateType> m_stateTypes;
StringMap<Part> m_parts;
uint8_t m_animatorVersion;
};
}
|