3 min read
Time Stasis

There’s a critical combat feature that I haven’t brought up yet. Stasis.

When you control a whole cabal, you cannot keep your eye on everything. I love the RTS genre, but a momentary pause mechanic can make the game much more strategic than purely tactical.

FTL used this to a great extent to give the feeling of being Captain Kirk barking orders after analyzing precisely what needed to be done to save the ship.

I want the lead of the cabal to have a similar feeling, so a Stasis mechanic (to theme it properly for fantasy) makes a lot of sense. However, I have a few considerations:

  • How should this be handled in multiplayer? Should it just be outright disabled? Limited?
  • Should the Stasis be tied to the chronomancer ability or unlockable via an upgrade?

Regardless of my future answer to those questions, it basically requires me to be able to freeze all game systems except user input processing and rendering. That is non-trivial to program. If I don’t implement it early and test it throughout development, I suspect it will never work properly.

Stasis Implementation

In order to get this to properly work, there were a few CommandSystems that I had to refactor and separate. My cast system handled spell input and created spells, but if I had to pause half the system, I should just separate them instead.

Currently, I have an InputSystem that handles turning user key/mouse/etc into Commands, which are stored in an InputComponent. (Yes, player input is a component and it belongs to a player entity). If I can disable all Systems that aren’t involved in either input/commands or my RenderSystem, that should pause the game but allow the user to continue to interact and plan.

I created a StasisPauseCommandSystem and a StasisPaused interface. I decided that Systems should declare whether they should be paused or not, that way I’ll make sure to update it as I go along.

The actual system ended up being incredibly simple. Here’s a sample of pausing:

public class StasisPauseCommandSystem extends EntitySystem {
  /** whether paused or not */
  public boolean isStasisPaused = false;

  public void stasisPause() {
      // disable anything that says it can be paused
      for (EntitySystem system : engine.getSystems()) {
          if (system instanceof StasisPaused) {
              system.setProcessing(false);
          }
      }
  }

  // function to handle command to stasis pause or not
}

And it really did just work.

stasis

Sometimes ECS can be clunky, but for this problem, it worked perfectly.

Now, I still need to show intent in my UI better - intended targets and intended movement. That should be as simple as adding effects to my UiRenderSystem as an underlay based on the Commands that are active.