good

Game Overdrive On Dart. The kernel the engine is built on: the ECS, the fixed-tick loop, scenes, native component storage, input, assets and coroutines. It knows nothing about 2D or 3D.

Building a 2D game? Install goo2d instead. It re-exports everything here, so you get this package anyway and a renderer with it. Depend on good directly when you are writing a renderer, a headless server, or a package that should work in either dimension.

flutter pub add good

The one idea

Components are not objects. A field declared on an entity kind is a column in native memory, and an entity is a row index into it:

import 'package:good/good.dart';

class Player extends EntityStruct {
  late final DataPointer<double> speed;

  @override
  void describeStruct(DataDescriptor data) {
    super.describeStruct(data);
    speed = data.hasFloat64(220);   // the default every new row starts at
  }
}
speed[entity] = 400;   // write one row

That is what keeps the frame loop free of allocation, and it is the thing worth understanding before anything else. Systems then query for the entities they care about and walk those columns:

class PlayerSystem extends GameSystem with FixedTickable {
  late final Query players;

  @override
  void describeQuery(QueryDescriptor descriptor) {
    super.describeQuery(descriptor);
    players = descriptor.query().withAll(Player).build();
  }

  @override
  void onFixedUpdate() { /* ... */ }
}

Next

It depends on Flutter, because GameView is a widget and StateChannel is a ValueListenable. Dimension-agnostic is not the same as Flutter-agnostic.

The ECS, memory pool, scheduler, scenes, hierarchy, input, assets, coroutines and timelines work today. Audio playback and array-typed fields are not implemented, and the web is unsupported because this needs dart:ffi and isolates. What works today.

Libraries

good
Dimension-agnostic engine kernel: ECS, shared memory pool, ring buffers, scenes, fixed-tick loop, hierarchy, and the generic asset registry.