osb/source/base/StarAnimatedPartSet.hpp

164 lines
5.9 KiB
C++
Raw Permalink Normal View History

#pragma once
2023-06-20 04:33:09 +00:00
#include "StarOrderedMap.hpp"
#include "StarJson.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;
JsonObject properties;
};
struct ActivePartInformation {
String partName;
// If a state match is found, this will be set.
Maybe<ActiveStateInformation> activeState;
JsonObject properties;
};
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;
};
2023-06-20 04:33:09 +00:00
AnimatedPartSet();
AnimatedPartSet(Json config);
// 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;
2023-06-20 04:33:09 +00:00
// 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);
// 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();
2023-06-20 04:33:09 +00:00
// 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 setActiveStateIndex(String const& stateTypeName, size_t stateIndex, bool alwaysStart = 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();
private:
static AnimationMode stringToAnimationMode(String const& string);
void freshenActiveState(StateType& stateType);
void freshenActivePart(Part& part);
OrderedHashMap<String, StateType> m_stateTypes;
StringMap<Part> m_parts;
};
}