/ #mechanics 

Time

“Time is an illusion.” – Albert Einstein

This is even more true in turn-based strategy games where turns usually abstract away the passage of a certain amount of time.

The time system should help accomplish a few things:

  • Give players a sense of the passage of time in the game world.
  • Enable scripted events that happen at a specific time.
  • Enable scripted events that happen at a certain frequency (e.g. every day or every week).

A good example of a time system in a turn-based strategy game is Heroes of Might and Magic:

  • Every day:
    • Towns, castles and gold mines produces gold.
    • Mines produce resources.
    • Heroes have their movement points replenished.
  • Every week:
    • Dwellings produce creatures.
    • Encounter buildings refill their rewards (e.g. Windmill)
    • Random chance of spawning mobs of monster all over the map.

ECS Design

Components

Clock

  • ticks: Integer

In this case ticks is an abstract measure of how much time has passed. You define how long a tick is in your game design. For example, Heroes of Might and Magic would have a tick equal to one day.

This component should be a Singleton as it is the global clock for the whole game.

TimedEvent

  • frequency: Integer
  • ticks: Integer

The ticks indicate how much time has passed.

When ticks is equal to frequency trigger the event by adding EventTrigger.

EventTrigger

A marker interface indicating that this TimedEvent has been triggered and should do whatever it does when it triggers.

Player

From the turn system. Use it to let your clock have a turn at the end of the round so that it can update the amount of time that has passed.

Active

From the turn system. Use it to let your clock have a turn at the end of the round so that it can update the amount of time that has passed.

EndTurn

From the turn system. Use it to let end your clock turn.

Entities

One clock entity with Clock and Player. When it gets Active as well, the turn is over.

So we increase the number of ticks on the Clock and update the ticks in each TimedEvent - if that event should trigger we reset the number of ticks and add EventTrigger to let it do whatever happens when it triggers.

Finally we add EndTurn to our clock to end its turn and let the next round start.

Systems

TimeSystem

The SystemName should be implemented aprroximately as follows (Python pseudo-code):

ticks_per_turn = 1
clocks = world.get_entities_with_component(Clock, Player, Active)

for clock in clocks:
    clock.clock.ticks += ticks_per_turn

    events = world.get_entities_with_component(TimedEvent)
    for event in events:
        event.timed_event.ticks += ticks_per_turn
        if event.timed_event.frequency == event.timed_event.ticks:
            event.timed_event.ticks = 0
            world.add_component(event, EventTrigger)
    
    world.add_component(clock, EndTurn)

EventSystem

This will actually be multiple systems - one for each type of TimedEvent you have.

events = world.get_entities_with_component(EventTrigger, TriggeredComponent)
for event in events:
    # Do whatever event.triggered_component does when it is triggered

    world.remove_component(event, EventTrigger)
Author

Matt Van Der Westhuizen

Back-end service developer at Ubisoft Blue Byte by day - wannabe game designer & developer by night.