Handmade Hero»Forums»Code
Rowan Crawford
13 posts
Architecting a sequencer
I recently added the ability to sequence a series of timed actions to my game, mostly for the playback of "scripted" events, sequences, and UI cleverness.

They were tedious to write, check, and bug find, and so I'm wondering if there is a smarter way to do this.

I'm using Objective-C and C, though the use of Objective-C is limited.

My current structure is essentially just a switch statement:

1
2
3
4
5
6
7
8
9
-(void)update:(float)aDelta
{
  playTime += aDelta;

  switch(programStep)
  {
    ...
  }
}


And each step/case is named in an enum something like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
enum ProgramSteps {
  eStep_InitialPause,
  eStep_ShowFirstObject,
  eStep_PauseAfterFirstObject,
  eStep_TypeUntilReachDots,
  eStep_LoopDots1,
  eStep_LoopDots2,
  eStep_LoopDots3
  eStep_End
};


And then each case in the switch goes something like this:

 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
case eStep_InitialPause:
{
  if(playTime >= aPauseLength) {
    playTime = 0.0f;
    programStep = ShowFirstObject;
  }
  break;
}

case eStep_ShowFirstObject:
{
  if(objectIsDead)
  {
    programStep = TypeUntilReachDots;
  }
  else 
  {
    objectLocation.x += objectSpeed * aDelta;

    if(objectLocation.x >= 1024)
    {
      programStep = PauseAfterFirstObject;
    }
  }
  break;
}

...
...

case eStep_LoopDots1:
case eStep_LoopDots2:
case eStep_LoopDots3:
{
  while(playTime >= typingSpeed)
  {
    playTime -= typingSpeed;
    charIndex++;

    if(charIndex == loopIndex)
    {
      charIndex -= 4;
      playTime = 0.0f;
      programStep++;
    }
  }
  break;
}


I found the pauses to be consistent throughout so I pulled that out into an inline helper function, but the others are all fairly unique.

The naming of the steps is something I only thought of after I considered writing this post, and after trying it in my code it improved editability immensely. Previously, each case was just incrementally numbered, so each insert or removal meant changing all the following numbers and everything that referenced anything that had changed: blegh.

But aside from that, I'm just wondering if I am on the right track with this, or is there something clever I'm overlooking?

Rowan.
Patrick Lahey
67 posts
Architecting a sequencer
It would be helpful to have more information. Depending on how you are handling events you might find a priority queue useful, but that is just a run time optimization which is not really what you are asking about.
Rowan Crawford
13 posts
Architecting a sequencer
It would be helpful to have more information. Depending on how you are handling events you might find a priority queue useful, but that is just a run time optimization which is not really what you are asking about.

There's not much more to it. If the program is running the game loop calls this update:aDelta each frame and the switch statement runs the code for the current step.

As for handling of events, I don't think I'm using anything like that in the sense you might be talking about (the game takes touch events from iOS, but that's about it).

Mention of a priority queue got me thinking of behaviour trees, which would be an interesting alternative to the way I've done it. Hmm. Something to play with.

Thanks.