Base structure

The very first step in the port is plugging Bevy's ECS. The source project has a mixed, game engine-wise, design:

  • the game loop is managed by the game engine (bracket-lib);
  • for each cycle (frame), an update is invoked on the ECS (Legion).

This is bare-bones structure of the source project:

// source: main.rs

struct State {
    ecs: World,
    resources: Resources,
    systems: Schedule,
}

impl State {
    fn new() -> Self {
        // [...]
        Self {
            ecs: World::default(),
            resources: Resources::default(),
            systems: build_scheduler(),
        }
    }
}

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        // [...]
        self.systems.execute(&mut self.ecs, &mut self.resources);
        render_draw_buffer(ctx).expect("Render error");
    }
}

fn main() -> BError {
    // [...]
    main_loop(context, State::new())
}

The translation is straightforward:

  • World and Resources map to App (which also owns the resources)
  • Legion's systems update for each tick maps to the App#update() API.

leading to:

// port: main.rs

struct State {
    ecs: App,
}

impl State {
    fn new() -> Self {
        // [...]
        Self { ecs: App::new() }
    }
}

impl GameState for State {
    fn tick(&mut self, ctx: &mut BTerm) {
        // [...]
        self.ecs.update();
        render_draw_buffer(ctx).expect("Render error");
    }
}