diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 89f60343..e0bfbed9 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -4,5 +4,6 @@ export 'board_side.dart'; export 'flipper.dart'; export 'pathway.dart'; export 'plunger.dart'; +export 'round_bumper.dart'; export 'score_points.dart'; export 'wall.dart'; diff --git a/lib/game/components/round_bumper.dart b/lib/game/components/round_bumper.dart new file mode 100644 index 00000000..37f02258 --- /dev/null +++ b/lib/game/components/round_bumper.dart @@ -0,0 +1,41 @@ +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:pinball/game/game.dart'; + +/// {@template round_bumper} +/// Circular body that repels a [Ball] on contact and increases the score. +/// {@endtemplate} +class RoundBumper extends BodyComponent with ScorePoints { + /// {@macro round_bumper} + RoundBumper({ + required Vector2 position, + required double radius, + required int points, + }) : _position = position, + _radius = radius, + _points = points; + + /// The position of the [RoundBumper] body. + final Vector2 _position; + + /// The radius of the [RoundBumper]. + final double _radius; + + /// Points awarded from hitting this [RoundBumper]. + final int _points; + + @override + int get points => _points; + + @override + Body createBody() { + final shape = CircleShape()..radius = _radius; + + final fixtureDef = FixtureDef(shape)..restitution = 1; + + final bodyDef = BodyDef() + ..position = _position + ..type = BodyType.static; + + return world.createBody(bodyDef)..createFixture(fixtureDef); + } +} diff --git a/test/game/components/round_bumper_test.dart b/test/game/components/round_bumper_test.dart new file mode 100644 index 00000000..f01ff13c --- /dev/null +++ b/test/game/components/round_bumper_test.dart @@ -0,0 +1,126 @@ +// 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'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('RoundBumper', () { + final flameTester = FlameTester(PinballGameTest.create); + const radius = 1.0; + const points = 1; + + flameTester.test( + 'loads correctly', + (game) async { + await game.ready(); + final roundBumper = RoundBumper( + position: Vector2.zero(), + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + + expect(game.contains(roundBumper), isTrue); + }, + ); + + flameTester.test( + 'has points', + (game) async { + final roundBumper = RoundBumper( + position: Vector2.zero(), + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + + expect(roundBumper.points, equals(points)); + }, + ); + + group('body', () { + flameTester.test( + 'positions correctly', + (game) async { + final position = Vector2.all(10); + final roundBumper = RoundBumper( + position: position, + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + game.contains(roundBumper); + + expect(roundBumper.body.position, equals(position)); + }, + ); + + flameTester.test( + 'is static', + (game) async { + final roundBumper = RoundBumper( + position: Vector2.zero(), + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + + expect(roundBumper.body.bodyType, equals(BodyType.static)); + }, + ); + }); + + group('fixture', () { + flameTester.test( + 'exists', + (game) async { + final roundBumper = RoundBumper( + position: Vector2.zero(), + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + + expect(roundBumper.body.fixtures[0], isA()); + }, + ); + + flameTester.test( + 'has restitution', + (game) async { + final roundBumper = RoundBumper( + position: Vector2.zero(), + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + + final fixture = roundBumper.body.fixtures[0]; + expect(fixture.restitution, greaterThan(0)); + }, + ); + + flameTester.test( + 'shape is circular', + (game) async { + final roundBumper = RoundBumper( + position: Vector2.zero(), + radius: radius, + points: points, + ); + await game.ensureAdd(roundBumper); + + final fixture = roundBumper.body.fixtures[0]; + expect(fixture.shape.shapeType, equals(ShapeType.circle)); + expect(fixture.shape.radius, equals(1)); + }, + ); + }); + }); +}