diff --git a/lib/game/components/anchor.dart b/lib/game/components/anchor.dart new file mode 100644 index 00000000..0e78aa1c --- /dev/null +++ b/lib/game/components/anchor.dart @@ -0,0 +1,32 @@ +import 'package:flame_forge2d/flame_forge2d.dart'; + +/// {@template anchor} +/// Non visual [BodyComponent] used to hold a [BodyType.dynamic] in [Joint]s +/// with this [BodyType.static]. +/// +/// It is recommended to [_position] the anchor first and then use the body +/// position as the anchor point when initializing a [JointDef]. +/// +/// ```dart +/// initialize( +/// dynamicBody.body, +/// anchor.body, +/// anchor.body.position, +/// ); +/// ``` +/// {@endtemplate} +class Anchor extends BodyComponent { + /// {@macro anchor} + Anchor({ + required Vector2 position, + }) : _position = position; + + final Vector2 _position; + + @override + Body createBody() { + final bodyDef = BodyDef()..position = _position; + + return world.createBody(bodyDef); + } +} diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 52e460a5..42c79ae6 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -1,3 +1,4 @@ +export 'anchor.dart'; export 'ball.dart'; export 'score_points.dart'; export 'wall.dart'; diff --git a/test/game/components/anchor_test.dart b/test/game/components/anchor_test.dart new file mode 100644 index 00000000..5cc37eca --- /dev/null +++ b/test/game/components/anchor_test.dart @@ -0,0 +1,60 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/game/game.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('Anchor', () { + final flameTester = FlameTester(PinballGame.new); + + flameTester.test( + 'loads correctly', + (game) async { + final anchor = Anchor(position: Vector2.zero()); + await game.ensureAdd(anchor); + + expect(game.contains(anchor), isTrue); + }, + ); + + group('body', () { + flameTester.test( + 'positions correctly', + (game) async { + final position = Vector2.all(10); + final anchor = Anchor(position: position); + await game.ensureAdd(anchor); + game.contains(anchor); + + expect(anchor.body.position, position); + }, + ); + + flameTester.test( + 'is static', + (game) async { + final anchor = Anchor(position: Vector2.zero()); + await game.ensureAdd(anchor); + + expect(anchor.body.bodyType, equals(BodyType.static)); + }, + ); + }); + + group('fixtures', () { + flameTester.test( + 'has none', + (game) async { + final anchor = Anchor(position: Vector2.zero()); + await game.ensureAdd(anchor); + + expect(anchor.body.fixtures, isEmpty); + }, + ); + }); + }); +}