esper icon indicating copy to clipboard operation
esper copied to clipboard

Add processor phases feature

Open acinis opened this issue 1 year ago • 6 comments

  • imports: Union and IntFlag
  • Processor.phases instance variable: allows IntFlag and bare int for default ~0
  • World.add_processor method: new optional arg _phases
  • World._process method: new arg _phases
  • World.process method: call to _process with ~0 (all flags set - all phases on)
  • World.process_phase method: new method, like process, but accepts phases arg

acinis avatar Aug 15 '23 10:08 acinis

Hi,

(Sorry if PRs without prior issue are not welcome here.)

This PR adds phases to world processing feature. It allows to define custom flags via enum.IntFlag, and choose which group of processors will be run.

It's usefull eg. when we have some logic systems that will be called at higher frequency than rendering system.

Note: I chose name phase cos:

  • group seems to me like entity grouping
  • batch is used in eg. pyglet and OpenGL
  • stage is used in libgdx

acinis avatar Aug 15 '23 10:08 acinis

A small usage example would be cool. I have a vague idea of skipping certain processors, but not 100% sure of a use case.

metaphist avatar Sep 11 '23 00:09 metaphist

# Example: Fixed update time step but with variable rendering

class Phase(enum.IntFlag):
    PHYSICS = enum.auto()
    RENDERING = enum.auto()

# TIME_PER_UPDATE is our fixed delta time
TIME_PER_UPDATE = 16 # Just an example, 16ms is about 60 FPS
acc = 0  # accumulator - how much time we are behind with simulation

while True:

    elapsed = get_elapsed_time()
    acc += elapsed

    handle_input()

    # Inner catch-up loop
    # When eg. user PC can't do so much processing in certain in-game situation
    # and we are behind with simulation, this loop will run few times...
    while acc >= TIME_PER_UPDATE:
        world.process_phase(Phase.PHYSICS, TIME_PER_UPDATE)
        acc -= TIME_PER_UPDATE

    # ... but rendering is run just once, so we lost few rendered frames,
    # but game world is still intact (eg. no bullet will fly through the wall).
    world.process_phase(Phase.RENDERING, TIME_PER_UPDATE)

I feel like this example is too minimal, but I hope it's clear how processing phases will be useful.

Also think about various supporting systems like caching, achievements, etc. These systems can be run at lower frequencies, but currently calling world.process() will run all systems at once.

So another example will be (with all systems at fixed time step):

  • physics - 120Hz
  • rendering - 60Hz
  • achievements - 1Hz

Also, in some (most?) ECS implementations systems are run manually, so we have full control how and when our systems will run. In this PR, everything will work as before. But if someone needs more control, there are additional methods for running only certain processing phase.

acinis avatar Sep 11 '23 17:09 acinis

Is it like using multiple World instances (or multiple contexts in v3) but separate processors can share data ? So there will be far fewer use cases for multiple contexts.

Felecarpp avatar Sep 11 '23 21:09 Felecarpp

Well, I think it's not like contexts. From https://github.com/benmoran56/esper/blob/esper3/esper/init.py

Each World is a dedicated context, and does not share Entities, Components, etc.

Phases will share everything, it's just a way to run some processors conditionally (less frequently or based on user setting, etc).

I think phases will play nicely with multiple worlds/contexts.

PS. Maybe I just choose bad name for phases.

acinis avatar Sep 11 '23 21:09 acinis

Sorry for the delay. Now that 3.0 is out and has gotten some testing, lets follow up on this. It's an interesting idea, and I can see how it can be useful.

I'm also not sure if phase is the best name for this. I can certainly understand the difficulty in choosing names :laughing: To me, stage and phase sound like it's always related to frequency. This might be a common case, but how about something more generic, like tag? Perhaps that's not any better :thinking:

benmoran56 avatar Oct 04 '23 01:10 benmoran56