Repository navigation
Expand file tree
/
Copy pathAnimationComponent.h
More file actions
141 lines (110 loc) · 5.29 KB
/
Copy pathAnimationComponent.h
File metadata and controls
141 lines (110 loc) · 5.29 KB
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
#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <functional>
#include <deki/Component.h>
#include "SpriteComponent.h"
#include <deki/assets/AssetRef.h>
#include "FrameAnimationData.h"
namespace Deki2D
{
/// Plays sprite frame animations from a .anim asset, which names
/// spritesheet frames by GUID.
DEKI_CATEGORY("2D")
DEKI_DESCRIPTION("Plays a frame animation asset on the object's sprite.")
class AnimationComponent : public Deki::Component
{
public:
SpriteComponent* spriteComponent;
DEKI_EXPORT
DEKI_TOOLTIP("A frame animation asset, which lists the frames and how long each is held.")
Deki::AssetRef<FrameAnimationData> animation; // .anim asset
FrameAnimationData* animationData; // Loaded frame animation data
bool ownsAnimationData; // True if this component deletes animationData
DEKI_EXPORT
DEKI_TOOLTIP("Which named sequence is playing, by index. Sequences are the separate animations inside one asset, "
"such as idle and walk.")
int32_t currentSequence;
DEKI_EXPORT
DEKI_TOOLTIP("Frame within the current sequence. Set it to scrub; it is also useful to read while debugging.")
int32_t currentFrame; // Index within the current sequence
uint32_t frameStartTime; // When the current frame started, in ms, on clockMs
// This animation's own clock, in ms: the sum of the engine's frame deltas
// (Deki::Time::GetDeltaTimeF), like every other per-frame update. The wall
// clock kept running through pauses and fixed-step frames (the editor's
// frame capture), so frames raced ahead of the movement they belong to.
float clockMs = 0.0f;
// Frame GUID -> SpriteFrame, resolved once per (sprite, animation data)
// pair so a frame change does not search the sheet by string. Rebuilt
// lazily when either pointer changes.
std::vector<std::vector<const SpriteFrame*>> resolvedFrames;
const Sprite* resolvedSprite = nullptr;
const FrameAnimationData* resolvedData = nullptr;
// The asset manager's epoch at resolve time. A reimported sprite can come
// back at the same address with new frames, which the pointers above
// cannot tell apart; the epoch moves on every reimport.
uint64_t resolvedEpoch = 0;
void ResolveFrames(const Sprite* sprite);
DEKI_EXPORT
DEKI_TOOLTIP(
"Whether the animation is advancing. Clearing this freezes it on the current frame rather than resetting it.")
bool isPlaying;
DEKI_EXPORT
DEKI_TOOLTIP("Set when a non-looping sequence reaches its last frame. Read it to know when to move on.")
bool hasFinished;
DEKI_EXPORT
DEKI_TOOLTIP(
"Play the current sequence once even if the asset marks it as looping. Cleared when the sequence changes.")
bool playOnceOverride;
std::function<void()> completionCallback; // Runs once when a non-looping play finishes
AnimationComponent(SpriteComponent* spriteComp = nullptr);
virtual ~AnimationComponent();
// Deki::Component overrides
void Awake() override;
void Update() override;
/// Takes the animation from the asset reference, finds the sprite
/// component on the same object if none is set, and starts the first
/// sequence.
void Setup();
/// Plays the current sequence from its first frame. When it is already
/// playing, restarts it only if `restartIfPlaying` is true.
void Play(bool restartIfPlaying = false);
/// Plays the sequence called `name` (such as "idle" or "walk"). Returns
/// false when there is no such sequence.
bool PlayAnimation(const char* name, bool restartIfPlaying = false);
/// Plays the current sequence once, even if it is set to loop.
void PlayOnce();
/// Plays the sequence called `name` once. Returns false when there is no
/// such sequence.
bool PlayAnimationOnce(const char* name);
/// Selects the sequence called `name` and shows its first frame without
/// playing it. Returns false when there is no such sequence.
bool SetAnimation(const char* name);
/// The current sequence's name, or an empty string when there is none.
const char* GetCurrentAnimationName() const;
int GetAnimationCount() const;
/// The name of sequence `index`, or an empty string when out of range.
const char* GetAnimationName(int index) const;
/// Stops playing and shows the first frame.
void Stop();
/// Stops playing and keeps the current frame.
void Pause();
/// Continues from the current frame.
void Resume();
/// True once a non-looping sequence has reached its last frame.
bool HasFinished() const { return hasFinished; }
/// Sets a function to run once when a non-looping sequence finishes.
void SetCompletionCallback(std::function<void()> callback) { completionCallback = callback; }
private:
/// The current sequence, or nullptr when the index is invalid.
const FrameAnimSequence* GetCurrentSequence() const;
/// The index of the sequence called `name`, or -1.
int FindAnimationIndex(const char* name) const;
/// Advances frames by the time passed. `currentTime` is in milliseconds.
void UpdateAnimation(uint32_t currentTime);
/// Shows the current frame on the sprite component.
void ApplyCurrentFrame();
void InitializeToFirstFrame();
};
} // namespace Deki2D