diff --git a/lib/game/components/baseboard.dart b/lib/game/components/baseboard.dart new file mode 100644 index 00000000..9802bccc --- /dev/null +++ b/lib/game/components/baseboard.dart @@ -0,0 +1,89 @@ +import 'package:flame/extensions.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:pinball/game/game.dart'; + +/// {@template baseboard} +/// TODO +/// {@endtemplate} +class Baseboard extends BodyComponent { + /// {@macro baseboard} + Baseboard._({ + required Vector2 position, + required this.side, + }) : _position = position; + + /// A left positioned [Baseboard]. + Baseboard.left({ + required Vector2 position, + }) : this._( + position: position, + side: BoardSide.left, + ); + + /// A right positioned [Baseboard]. + Baseboard.right({ + required Vector2 position, + }) : this._( + position: position, + side: BoardSide.right, + ); + + /// The width of the [Baseboard]. + static const width = 10.0; + + /// The height of the [Baseboard]. + static const height = 2.0; + + /// The position of the [Baseboard] body. + final Vector2 _position; + + /// Whether the [Baseboard] is on the left or right side of the board. + final BoardSide side; + + List _createFixtureDefs() { + final fixtures = []; + + final circleShape1 = CircleShape()..radius = Baseboard.height / 2; + circleShape1.position.setValues( + -(Baseboard.width / 2) + circleShape1.radius, + 0, + ); + final circle1FixtureDef = FixtureDef(circleShape1); + fixtures.add(circle1FixtureDef); + + final circleShape2 = CircleShape()..radius = Baseboard.height / 2; + circleShape2.position.setValues( + (Baseboard.width / 2) - circleShape2.radius, + 0, + ); + final circle2FixtureDef = FixtureDef(circleShape2); + fixtures.add(circle2FixtureDef); + + final rectangle = PolygonShape() + ..setAsBox( + (Baseboard.width - Baseboard.height) / 2, + Baseboard.height / 2, + (circleShape1.position + circleShape2.position) / 2, + 0, + ); + final rectangleFixtureDef = FixtureDef(rectangle); + fixtures.add(rectangleFixtureDef); + + return fixtures; + } + + @override + Body createBody() { + final angle = radians(27); + + final bodyDef = BodyDef() + ..position = _position + ..type = BodyType.static + ..angle = side.isLeft ? -angle : angle; + + final body = world.createBody(bodyDef); + _createFixtureDefs().forEach(body.createFixture); + + return body; + } +} diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 89f60343..bcf9a92d 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -1,5 +1,6 @@ export 'anchor.dart'; export 'ball.dart'; +export 'baseboard.dart'; export 'board_side.dart'; export 'flipper.dart'; export 'pathway.dart'; diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 5854422c..f5fa56e6 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -43,6 +43,8 @@ class PinballGame extends Forge2DGame addContactCallback(BottomWallBallContactCallback()); unawaited(_addFlippers()); + + await _addBaseboards(); } Future _addFlippers() async { @@ -104,4 +106,28 @@ class PinballGame extends Forge2DGame ), ); } + + Future _addBaseboards() async { + final spaceBetweenBaseboards = camera.viewport.effectiveSize.x / 2; + + final leftBaseboard = Baseboard.left( + position: screenToWorld( + Vector2( + camera.viewport.effectiveSize.x / 2 - (spaceBetweenBaseboards / 2), + camera.viewport.effectiveSize.y / 1.17, + ), + ), + ); + await add(leftBaseboard); + + final rightBaseboard = Baseboard.right( + position: screenToWorld( + Vector2( + camera.viewport.effectiveSize.x / 2 + (spaceBetweenBaseboards / 2), + camera.viewport.effectiveSize.y / 1.17, + ), + ), + ); + await add(rightBaseboard); + } } diff --git a/test/game/components/baseboard_test.dart b/test/game/components/baseboard_test.dart new file mode 100644 index 00000000..7463fccf --- /dev/null +++ b/test/game/components/baseboard_test.dart @@ -0,0 +1,86 @@ +// 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() { + group('Baseboard', () { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(PinballGameX.initial); + + flameTester.test( + 'loads correctly', + (game) async { + await game.ready(); + final leftBaseboard = Baseboard.left(position: Vector2.zero()); + final rightBaseboard = Baseboard.right(position: Vector2.zero()); + await game.ensureAddAll([leftBaseboard, rightBaseboard]); + + expect(game.contains(leftBaseboard), isTrue); + expect(game.contains(rightBaseboard), isTrue); + }, + ); + + group('constructor', () { + test('sets BoardSide', () { + final leftBaseboard = Baseboard.left(position: Vector2.zero()); + expect(leftBaseboard.side, equals(leftBaseboard.side)); + + final rightBaseboard = Baseboard.right(position: Vector2.zero()); + expect(rightBaseboard.side, equals(rightBaseboard.side)); + }); + }); + + group('body', () { + flameTester.test( + 'positions correctly', + (game) async { + final position = Vector2.all(10); + final baseboard = Baseboard.left(position: position); + await game.ensureAdd(baseboard); + game.contains(baseboard); + + expect(baseboard.body.position, position); + }, + ); + + flameTester.test( + 'is static', + (game) async { + final baseboard = Baseboard.left(position: Vector2.zero()); + await game.ensureAdd(baseboard); + + expect(baseboard.body.bodyType, equals(BodyType.static)); + }, + ); + + flameTester.test( + 'is at an angle', + (game) async { + final leftBaseboard = Baseboard.left(position: Vector2.zero()); + final rightBaseboard = Baseboard.right(position: Vector2.zero()); + await game.ensureAddAll([leftBaseboard, rightBaseboard]); + + expect(leftBaseboard.body.angle, isNegative); + expect(rightBaseboard.body.angle, isPositive); + }, + ); + }); + + group('fixtures', () { + flameTester.test( + 'has three', + (game) async { + final baseboard = Baseboard.left(position: Vector2.zero()); + await game.ensureAdd(baseboard); + + expect(baseboard.body.fixtures.length, equals(3)); + }, + ); + }); + }); +}