feat: add baseboards (#34)

* feat: add baseboards

* docs: baseboard

* fix: test extension

* chore: simplify rectangle

* refactor: PR suggestions
pull/41/head
Allison Ryan 2 years ago committed by GitHub
parent ddec3c0f44
commit f6f171b7c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,91 @@
import 'dart:math' as math;
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/game.dart';
/// {@template baseboard}
/// Straight, angled board piece to corral the [Ball] towards the [Flipper]s.
/// {@endtemplate}
class Baseboard extends BodyComponent {
/// {@macro baseboard}
Baseboard._({
required Vector2 position,
required BoardSide side,
}) : _position = position,
_side = side;
/// 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<FixtureDef> _createFixtureDefs() {
final fixtures = <FixtureDef>[];
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()
..setAsBoxXY(
(Baseboard.width - Baseboard.height) / 2,
Baseboard.height / 2,
);
final rectangleFixtureDef = FixtureDef(rectangle);
fixtures.add(rectangleFixtureDef);
return fixtures;
}
@override
Body createBody() {
// TODO(allisonryan0002): share sweeping angle with flipper when components
// are grouped.
const angle = math.pi / 7;
final bodyDef = BodyDef()
..position = _position
..type = BodyType.static
..angle = _side.isLeft ? -angle : angle;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
}

@ -1,5 +1,6 @@
export 'anchor.dart';
export 'ball.dart';
export 'baseboard.dart';
export 'board_side.dart';
export 'flipper.dart';
export 'pathway.dart';

@ -63,6 +63,7 @@ class PinballGame extends Forge2DGame
),
),
);
unawaited(_addBaseboards());
}
void spawnBall() {
@ -103,6 +104,31 @@ class PinballGame extends Forge2DGame
),
);
}
Future<void> _addBaseboards() async {
final spaceBetweenBaseboards = camera.viewport.effectiveSize.x / 2;
final baseboardY = camera.viewport.effectiveSize.y / 1.12;
final leftBaseboard = Baseboard.left(
position: screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 2 - (spaceBetweenBaseboards / 2),
baseboardY,
),
),
);
await add(leftBaseboard);
final rightBaseboard = Baseboard.right(
position: screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 2 + (spaceBetweenBaseboards / 2),
baseboardY,
),
),
);
await add(rightBaseboard);
}
}
class DebugPinballGame extends PinballGame with TapDetector {

@ -0,0 +1,76 @@
// 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(PinballGameTest.create);
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('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));
},
);
});
});
}

@ -74,6 +74,15 @@ void main() {
returnsNormally,
);
});
flameTester.test(
'has two Baseboards',
(game) async {
await game.ready();
final baseboards = game.children.whereType<Baseboard>().toList();
expect(baseboards.length, 2);
},
);
});
debugModeFlameTester.test('adds a ball on tap up', (game) async {

Loading…
Cancel
Save