diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000000..25302769b70 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,20 @@ +name: Benchmark + +on: [pull_request] + +jobs: + benchmark: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: subosito/flutter-action@v2 + - uses: bluefireteam/melos-action@v3 + + - uses: luanpotter/dart-benchmark-action@v0.1.13 + with: + paths: "packages/flame/" + ignore-tag: "no-benchmark" + is-flutter: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/packages/flame/benchmark/main.dart b/packages/flame/benchmark/main.dart new file mode 100644 index 00000000000..cc6d8f98da8 --- /dev/null +++ b/packages/flame/benchmark/main.dart @@ -0,0 +1,5 @@ +import 'update_components_benchmark.dart'; + +Future main() async { + await UpdateComponentsBenchmark.main(); +} diff --git a/packages/flame/benchmark/update_components_benchmark.dart b/packages/flame/benchmark/update_components_benchmark.dart new file mode 100644 index 00000000000..05667491d17 --- /dev/null +++ b/packages/flame/benchmark/update_components_benchmark.dart @@ -0,0 +1,96 @@ +import 'dart:math'; + +import 'package:benchmark_harness/benchmark_harness.dart'; +import 'package:flame/components.dart'; +import 'package:flame/game.dart'; + +const _amountComponents = 20; +const _amountTicks = 1000; +const _amountInputs = 100; + +class UpdateComponentsBenchmark extends AsyncBenchmarkBase { + final Random random; + + late final FlameGame _game; + late final List<_BenchmarkComponent> _components; + late final List _dts; + late final Set _inputTicks; + + UpdateComponentsBenchmark(this.random) + : super('Updating Components Benchmark'); + + static Future main() async { + final r = Random(69420); + await UpdateComponentsBenchmark(r).report(); + } + + @override + Future setup() async { + _game = FlameGame(); + await _game.addAll( + List.generate(_amountComponents, _BenchmarkComponent.new), + ); + + await _game.ready(); + + _components = + _game.children.whereType<_BenchmarkComponent>().toList(growable: false); + + _dts = List.generate(_amountTicks, (_) => random.nextDouble()); + _inputTicks = List.generate( + _amountInputs, + (_) => random.nextInt(_amountTicks), + ).toSet(); + } + + @override + Future exercise() async { + for (final (idx, dt) in _dts.indexed) { + if (_inputTicks.contains(idx)) { + _components[random.nextInt(_amountComponents)].input( + xDirection: random.nextInt(3) - 1, + doJump: random.nextBool(), + ); + } + _game.update(dt); + } + } +} + +class _BenchmarkComponent extends PositionComponent { + static const _groundY = -20.0; + + final int id; + final Vector2 velocity = Vector2.zero(); + + _BenchmarkComponent(this.id); + + void input({ + required int xDirection, + required bool doJump, + }) { + // move x + velocity.x = xDirection * 100; + + // jump + if (position.y == _groundY) { + velocity.y -= 100; + } + } + + @override + void update(double dt) { + super.update(dt); + + position.add(velocity * dt); + velocity.add(Vector2(0, 10 * dt)); + + if (position.y > _groundY) { + position.y = _groundY; + velocity.setValues(0, 0); + } + } + + @override + String toString() => '[Component $id]'; +} diff --git a/packages/flame/pubspec.yaml b/packages/flame/pubspec.yaml index 78358c5c7ef..d20affb8990 100644 --- a/packages/flame/pubspec.yaml +++ b/packages/flame/pubspec.yaml @@ -25,6 +25,7 @@ dependencies: vector_math: ^2.1.4 dev_dependencies: + benchmark_harness: ^2.3.1 canvas_test: ^0.2.0 dartdoc: ^8.0.8 flame_lint: ^1.2.1