Timed Sequences - JayhawkZombie/EECS581Project GitHub Wiki
--
In SFEngine > Source > Headers > Time > TimedSequence.h
The engine contains a class, TimedSequence
, that can be used for chaining sequences of actions, invoking each specified action for a specified amount of time.
There are 2 classes used for this:
The SequenceNode
class is used to store one action, callbacks for that action, and do individual timing for that action.
The class stores 3 registered callbacks, one for when the sequenced action begins, one for every frame update during the action, and one for when the sequenced action completes (i.e. time runs out).
Methods
SequenceNode(const SequenceNode &Copy)
- copy constructor
SequenceNode(std::initializer_list<SequenceNode> Seq)
- initializer list constructor
SequenceNode(double delta, std::function<void(void)> start, std::function<void(void)> update, std::function<void(void)> end)
- Typical constructor, passing in the amount of time (in milliseconds) for the action to take place, and the 3 needed function callbacks
void TickUpdate(const double &delta)
- called every frame to update the timing
bool IsDone() const
- test if the action is done
void Start()
- called when the action starts
void End()
- called when the action is done
This class stores a std::queue
of SequenceNode
instances, and one-by-one updates them every frame and ensures the proper invocation of registered callbacks.
Methods
-
Add a single sequence to the queue
void AddSequence( double Duration, std::function<void(void)> StartCB, std::function<void(void)> Update, std::function<void(void)> EndCB );
-
Add multiple sequences to the queue
void AddSequences( std::function<void(void)> Start, std::function<void(void)> Update, std::function<void(void)> End, std::initializer_list<SequenceNode> Nodes );
void Start()
- begin the sequence timing and execution
void TickUpdate(const double &delta)
- update the sequence
void SetUpdateCallback(std::function<void(const double &)> CB)
- set the function to be invoked for every frame update
Members
bool m_IsTiming
- Is the sequence timing/active
std::queue<SequenceNode> m_Nodes
- stored queue of SequenceNodes
std::function<void(void)> m_StartCallBack
- function to call when starting the entire sequence
std::function<void(void)> m_EndCallBack
- function to call when the entire sequence is complete
std::function<void(const double &)> m_UpdateCallBack
- function to call every frame update
In Projects > PuzzleDemo > Classes > StartupLevel.cpp
there is a lightning animation. Each letter being struck and subsequently being surrounded in lightning is timed using this class.
After the positions of the future bolts is computed and stored, the sequence is stored as m_LightningSequence
and the sequence of bolt strikes is created as follows:
m_LightningSequence.AddSequences(
[this]() {this->LightningSequenceStarted(); }, //CB for the lightning sequence starting
[]() {}, //CB for frame updates -> empty because this sequence does not need to update every frame, the bolts handle that themselves
[this]() {this->LightningSequenceEnded(); }, //CB for the lightning sequence ending
{
{ 400.0, [this]() { this->LightningSequenceCB(0, 1, 2, 3); }, []() {}, []() {} }, // 4 bolts strike the 'S' character
{ 400.0, [this]() { this->LightningSequenceCB(4, 5, 6, 7); }, []() {}, []() {} }, // 4 botls strike the 'F' character
{ 400.0, [this]() { this->LightningSequenceCB(8, 9, 10, 11); }, []() {}, []() {} }, // 4 botls strike the 'F' character
{ 400.0, [this]() { this->LightningSequenceCB(12, 13, 14, 15); }, []() {}, []() {} }, // 4 botls strike the 'F' character
{ 400.0, [this]() { this->LightningSequenceCB(16, 17, 18, 19); }, []() {}, []() {} }, // 4 botls strike the 'F' character
{ 400.0, [this]() { this->LightningSequenceCB(20, 21, 22, 23); }, []() {}, []() {} }, // 4 botls strike the 'F' character
{ 400.0, [this]() { this->LightningSequenceCB(24, 25, 26, 27); }, []() {}, []() {} }, // 4 botls strike the 'F' character
{ 400.0, [this]() { this->LightningSequenceCB(28, 29, 30, 31); }, []() {}, []() {} }, // 4 botls strike the 'F' character
}
);
The first 3 lines define the functions to be called when the sequence starts/updates/completes:
[this]() {this->LightningSequenceStarted(); }, //CB for the lightning sequence starting
[]() {}, //CB for frame updates -> empty because this sequence does not need to update every frame, the bolts handle that themselves
[this]() {this->LightningSequenceEnded(); }, //CB for the lightning sequence ending
-
For the starting callback, we've passed:
[this]() {this->LightningSequenceStarted(); }
, a lambda function invokingLightningSequenceStarted
onthis
-
For the update callback, we've passed:
[]() {}
, a completely empty lambda. This callback must be defined, however, so sending an empty lambda is the only way to ensure nothing actually happens -
For the ending callback, we've passed:
[this]() {this->LightningSequenceEnded(); }
, a lambda function invokingLightningSequenceEnded
onthis
In this example, there are 32 separate "crawling" lightning bolts, 4 for each letter of "SFENGINE".
In the list of sequences inside AddSequences
we set up the timing for those.
Look at the first SequenceNode being created in the initializer list:
{ 400.0, [this]() { this->LightningSequenceCB(0, 1, 2, 3); }, []() {}, []() {} }
For Duration
, we are passing 400.0
, meaning this particular action in the sequence will last 400.0ms.
For the starting callback, we are passing [this]() { this->LightningSequenceCB(0, 1, 2, 3); }
, a lambda that calls LightningSequenceCB
on this
and passes 0, 1, 2, 3
as parameters because this action is causing the first 4 bolts to begin to make out the shape of the first letter, S.
The other 2 parameters are left empty, because we do not want to update anything, and we don't need to be notified of when the 400.0ms is over, since the lightning bolts can manage their own lifetime.
There are 8 SequenceNodes being created, one for every letter of "SFENGINE". When one of these is finished, the TimedSequence class will pop the node off the queue and move on to the next one, invoking the ending callback for the completed node and the starting callback for the next node. When all nodes have completed, the ending callback for the entire sequence is invoked.