Timed Sequences - JayhawkZombie/EECS581Project GitHub Wiki

Timed Sequences

--
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:

SequenceNode

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

TimedSequence

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

Example of usage

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 invoking LightningSequenceStarted on this

  • 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 invoking LightningSequenceEnded on this

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.

⚠️ **GitHub.com Fallback** ⚠️