Branch, Race, Sync clarification

In the Butterfly demo, you use branch to start the _fly and _animate__wing__material coroutines in the constructor. Is there a reason why you didn’t use a race?

In _fly, you use the following race:

  race
  [
  loop
    [
    move_flight(45 35) // Move and rotate        
    animate_flight     // Animate wing/body components        
    _wait              // Wait one frame
    ]
    
  _wait(1.8)  
  ]

If I’m understanding correctly, this says loop through the take off animations for 1.8 seconds then run the code handling the flight phase. In that phase, you have 3 loops, and I think the “check_for_landing_spot” loop is what actually causes the race to exit.

How am I doing?

The reason that a branch is used in a constructor is that constructor is a method and methods can only call other expressions that return instantly. Coroutines can take more than one frame to complete and branch will make one or more coroutines return immediately - even if sub-expressions of the branch continue on after it completes.

Here is a post that goes into more detail on the branch command.

A race expression will still last as long as the shortest time of each of its expressions - which may be several frames and thus may not instantly complete.

The same holds true with sync - it will last as long as the longest time of each of its expressions - and thus may not instantly complete.

I hadn’t yet understood that methods must only call expressions which return immediately. When you’re working on the documentation, that would be an important distinction to highlight. With this explanation, using branch in the constructor makes perfect sense.

So if methods must only call expressions which finish within one frame, does that mean calling a method can decrease the frame rate if it takes a long time to run?

1 Like

Yes, having methods that take a long time to complete can in theory decrease the frame rate.

In practice this is not usually an issue.

Most of the time SkookumScript responds to events and sets engine actions in motion - most of the work in any given frame is spent in the engine runtime.

Using Sleeping Dogs as an example, it had a large team of scripters pumping out tons of scripts for a large open world game and they did not need to expend much mental energy on performance. I would say that SkookumScript was much more of an aid to performance than a hindrance.

An older ancestor language of SkookumScript spread script updating across frames and guaranteed the scripting system only spent so much time in any given timeslice. However this required the internal language runtime to be significantly more complex and all aspects of the language needed to be reentrant. This additional overhead had a large performance hit that was beyond the control of developers using the language and it made the language much harder to extend and enhance. It was one of those great ideas that turns out to be not so great once you see it in the field on real projects.

Here is a longer post discussing SkookumScript performance: