feat: group Baseboards and Flipper (#47)

* feat: connected baseboards to flipper

* chore: removed FlipperGroup

* refactor: simplified Baseboard constructor

* refactor: simplified BottomGroup

* refactor: changed constructors

* refactor: removed unecessary import

* refactor: modified Flipper constructor

* docs: updated doc comment

* docs: used macro for BottomGroupSide

* docs: improved doc comment

* refactor: renamed magnitude to direction

* refactor: renamed bumper to baseboard

* feat: included board tests

* docs: improved doc comment

* feat: include boardSide.direction (#46)

* feat: implemented BoardSide.direction

* docs: included doc comment

* refactor: used _side.direction

* refactor: used ensureAdd

* chore: removed old test

* docs: improved comments
pull/48/head
Alejandro Santiago 4 years ago committed by GitHub
parent 413900e89f
commit 7a8f808822
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -8,27 +8,11 @@ import 'package:pinball/game/game.dart';
/// {@endtemplate} /// {@endtemplate}
class Baseboard extends BodyComponent { class Baseboard extends BodyComponent {
/// {@macro baseboard} /// {@macro baseboard}
Baseboard._({ Baseboard({
required Vector2 position,
required BoardSide side, 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, required Vector2 position,
}) : this._( }) : _side = side,
position: position, _position = position;
side: BoardSide.right,
);
/// The width of the [Baseboard]. /// The width of the [Baseboard].
static const width = 10.0; static const width = 10.0;

@ -0,0 +1,76 @@
import 'package:flame/components.dart';
import 'package:pinball/game/game.dart';
/// {@template bottom_group}
/// Grouping of the board's bottom [Component]s.
///
/// The bottom [Component]s are the [Flipper]s and the [Baseboard]s.
/// {@endtemplate}
// TODO(alestiago): Add [SlingShot] once provided.
// TODO(alestiago): Consider renaming once entire Board is defined.
class BottomGroup extends Component {
/// {@macro bottom_group}
BottomGroup({
required this.position,
required this.spacing,
});
/// The amount of space between the line of symmetry.
final double spacing;
/// The position of this [BottomGroup].
final Vector2 position;
@override
Future<void> onLoad() async {
final spacing = this.spacing + Flipper.width / 2;
final rightSide = _BottomGroupSide(
side: BoardSide.right,
position: position + Vector2(spacing, 0),
);
final leftSide = _BottomGroupSide(
side: BoardSide.left,
position: position + Vector2(-spacing, 0),
);
await addAll([rightSide, leftSide]);
}
}
/// {@template bottom_group_side}
/// Group with one side of [BottomGroup]'s symmetric [Component]s.
///
/// For example, [Flipper]s are symmetric components.
/// {@endtemplate}
class _BottomGroupSide extends Component {
/// {@macro bottom_group_side}
_BottomGroupSide({
required BoardSide side,
required Vector2 position,
}) : _side = side,
_position = position;
final BoardSide _side;
final Vector2 _position;
@override
Future<void> onLoad() async {
final direction = _side.direction;
final flipper = Flipper.fromSide(
side: _side,
position: _position,
);
final baseboard = Baseboard(
side: _side,
position: _position +
Vector2(
(Flipper.width * direction) - direction,
Flipper.height,
),
);
await addAll([flipper, baseboard]);
}
}

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

@ -8,42 +8,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
/// {@template flipper_group}
/// Loads a [Flipper.right] and a [Flipper.left].
/// {@endtemplate}
class FlipperGroup extends Component {
/// {@macro flipper_group}
FlipperGroup({
required this.position,
required this.spacing,
});
/// The amount of space between the [Flipper.right] and [Flipper.left].
final double spacing;
/// The position of this [FlipperGroup]
final Vector2 position;
@override
Future<void> onLoad() async {
final leftFlipper = Flipper.left(
position: Vector2(
position.x - (Flipper.width / 2) - (spacing / 2),
position.y,
),
);
await add(leftFlipper);
final rightFlipper = Flipper.right(
position: Vector2(
position.x + (Flipper.width / 2) + (spacing / 2),
position.y,
),
);
await add(rightFlipper);
}
}
/// {@template flipper} /// {@template flipper}
/// A bat, typically found in pairs at the bottom of the board. /// A bat, typically found in pairs at the bottom of the board.
/// ///
@ -58,8 +22,7 @@ class Flipper extends BodyComponent with KeyboardHandler {
}) : _position = position, }) : _position = position,
_keys = keys; _keys = keys;
/// A left positioned [Flipper]. Flipper._left({
Flipper.left({
required Vector2 position, required Vector2 position,
}) : this._( }) : this._(
position: position, position: position,
@ -70,8 +33,7 @@ class Flipper extends BodyComponent with KeyboardHandler {
], ],
); );
/// A right positioned [Flipper]. Flipper._right({
Flipper.right({
required Vector2 position, required Vector2 position,
}) : this._( }) : this._(
position: position, position: position,
@ -82,6 +44,22 @@ class Flipper extends BodyComponent with KeyboardHandler {
], ],
); );
/// Constructs a [Flipper] from a [BoardSide].
///
/// A [Flipper._right] and [Flipper._left] besides being mirrored
/// horizontally, also have different [LogicalKeyboardKey]s that control them.
factory Flipper.fromSide({
required BoardSide side,
required Vector2 position,
}) {
switch (side) {
case BoardSide.left:
return Flipper._left(position: position);
case BoardSide.right:
return Flipper._right(position: position);
}
}
/// Asset location of the sprite that renders with the [Flipper]. /// Asset location of the sprite that renders with the [Flipper].
/// ///
/// Sprite is preloaded by [PinballGameAssetsX]. /// Sprite is preloaded by [PinballGameAssetsX].

@ -48,9 +48,20 @@ class PinballGame extends Forge2DGame
), ),
); );
unawaited(_addFlippers());
unawaited(_addBonusWord()); unawaited(_addBonusWord());
unawaited(
add(
BottomGroup(
position: screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 2,
camera.viewport.effectiveSize.y / 1.25,
),
),
spacing: 2,
),
),
);
} }
Future<void> _addBonusWord() async { Future<void> _addBonusWord() async {
@ -66,25 +77,6 @@ class PinballGame extends Forge2DGame
); );
} }
Future<void> _addFlippers() async {
final flippersPosition = screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 2,
camera.viewport.effectiveSize.y / 1.1,
),
);
unawaited(
add(
FlipperGroup(
position: flippersPosition,
spacing: 2,
),
),
);
unawaited(_addBaseboards());
}
void spawnBall() { void spawnBall() {
add(Ball(position: plunger.body.position)); add(Ball(position: plunger.body.position));
} }
@ -115,31 +107,6 @@ 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 { class DebugPinballGame extends PinballGame with TapDetector {

@ -14,8 +14,14 @@ void main() {
'loads correctly', 'loads correctly',
(game) async { (game) async {
await game.ready(); await game.ready();
final leftBaseboard = Baseboard.left(position: Vector2.zero()); final leftBaseboard = Baseboard(
final rightBaseboard = Baseboard.right(position: Vector2.zero()); position: Vector2.zero(),
side: BoardSide.left,
);
final rightBaseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.right,
);
await game.ensureAddAll([leftBaseboard, rightBaseboard]); await game.ensureAddAll([leftBaseboard, rightBaseboard]);
expect(game.contains(leftBaseboard), isTrue); expect(game.contains(leftBaseboard), isTrue);
@ -28,7 +34,10 @@ void main() {
'positions correctly', 'positions correctly',
(game) async { (game) async {
final position = Vector2.all(10); final position = Vector2.all(10);
final baseboard = Baseboard.left(position: position); final baseboard = Baseboard(
position: position,
side: BoardSide.left,
);
await game.ensureAdd(baseboard); await game.ensureAdd(baseboard);
game.contains(baseboard); game.contains(baseboard);
@ -39,7 +48,10 @@ void main() {
flameTester.test( flameTester.test(
'is static', 'is static',
(game) async { (game) async {
final baseboard = Baseboard.left(position: Vector2.zero()); final baseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(baseboard); await game.ensureAdd(baseboard);
expect(baseboard.body.bodyType, equals(BodyType.static)); expect(baseboard.body.bodyType, equals(BodyType.static));
@ -49,8 +61,14 @@ void main() {
flameTester.test( flameTester.test(
'is at an angle', 'is at an angle',
(game) async { (game) async {
final leftBaseboard = Baseboard.left(position: Vector2.zero()); final leftBaseboard = Baseboard(
final rightBaseboard = Baseboard.right(position: Vector2.zero()); position: Vector2.zero(),
side: BoardSide.left,
);
final rightBaseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.right,
);
await game.ensureAddAll([leftBaseboard, rightBaseboard]); await game.ensureAddAll([leftBaseboard, rightBaseboard]);
expect(leftBaseboard.body.angle, isNegative); expect(leftBaseboard.body.angle, isNegative);
@ -63,7 +81,10 @@ void main() {
flameTester.test( flameTester.test(
'has three', 'has three',
(game) async { (game) async {
final baseboard = Baseboard.left(position: Vector2.zero()); final baseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(baseboard); await game.ensureAdd(baseboard);
expect(baseboard.body.fixtures.length, equals(3)); expect(baseboard.body.fixtures.length, equals(3));

@ -0,0 +1,68 @@
// 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();
final flameTester = FlameTester(Forge2DGame.new);
group('BottomGroup', () {
flameTester.test(
'loads correctly',
(game) async {
final bottomGroup = BottomGroup(position: Vector2.zero(), spacing: 0);
await game.ready();
await game.ensureAdd(bottomGroup);
expect(game.contains(bottomGroup), isTrue);
},
);
group('children', () {
flameTester.test(
'has one left flipper',
(game) async {
final bottomGroup = BottomGroup(position: Vector2.zero(), spacing: 0);
await game.ready();
await game.ensureAdd(bottomGroup);
final leftFlippers = bottomGroup.findNestedChildren<Flipper>(
condition: (flipper) => flipper.side.isLeft,
);
expect(leftFlippers.length, equals(1));
},
);
flameTester.test(
'has one right flipper',
(game) async {
final bottomGroup = BottomGroup(position: Vector2.zero(), spacing: 0);
await game.ready();
await game.ensureAdd(bottomGroup);
final leftFlippers = bottomGroup.findNestedChildren<Flipper>(
condition: (flipper) => flipper.side.isRight,
);
expect(leftFlippers.length, equals(1));
},
);
flameTester.test(
'has two Baseboards',
(game) async {
final bottomGroup = BottomGroup(position: Vector2.zero(), spacing: 0);
await game.ready();
await game.ensureAdd(bottomGroup);
final leftFlippers = bottomGroup.findNestedChildren<Baseboard>();
expect(leftFlippers.length, equals(2));
},
);
});
});
}

@ -2,7 +2,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -15,110 +14,20 @@ void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(PinballGameTest.create); final flameTester = FlameTester(PinballGameTest.create);
group('FlipperGroup', () {
flameTester.test(
'loads correctly',
(game) async {
final flipperGroup = FlipperGroup(
position: Vector2.zero(),
spacing: 0,
);
await game.ensureAdd(flipperGroup);
expect(game.contains(flipperGroup), isTrue);
},
);
group('constructor', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final flipperGroup = FlipperGroup(
position: position,
spacing: 0,
);
await game.ensureAdd(flipperGroup);
expect(flipperGroup.position, equals(position));
},
);
});
group('children', () {
bool Function(Component) flipperSelector(BoardSide side) =>
(component) => component is Flipper && component.side == side;
flameTester.test(
'has only one left Flipper',
(game) async {
final flipperGroup = FlipperGroup(
position: Vector2.zero(),
spacing: 0,
);
await game.ensureAdd(flipperGroup);
expect(
() => flipperGroup.children.singleWhere(
flipperSelector(BoardSide.left),
),
returnsNormally,
);
},
);
flameTester.test(
'has only one right Flipper',
(game) async {
final flipperGroup = FlipperGroup(
position: Vector2.zero(),
spacing: 0,
);
await game.ensureAdd(flipperGroup);
expect(
() => flipperGroup.children.singleWhere(
flipperSelector(BoardSide.right),
),
returnsNormally,
);
},
);
flameTester.test(
'spaced correctly',
(game) async {
final flipperGroup = FlipperGroup(
position: Vector2.zero(),
spacing: 2,
);
await game.ready();
await game.ensureAdd(flipperGroup);
final leftFlipper = flipperGroup.children.singleWhere(
flipperSelector(BoardSide.left),
) as Flipper;
final rightFlipper = flipperGroup.children.singleWhere(
flipperSelector(BoardSide.right),
) as Flipper;
expect(
leftFlipper.body.position.x + Flipper.width + flipperGroup.spacing,
equals(rightFlipper.body.position.x),
);
},
);
});
});
group( group(
'Flipper', 'Flipper',
() { () {
flameTester.test( flameTester.test(
'loads correctly', 'loads correctly',
(game) async { (game) async {
final leftFlipper = Flipper.left(position: Vector2.zero()); final leftFlipper = Flipper.fromSide(
final rightFlipper = Flipper.right(position: Vector2.zero()); side: BoardSide.left,
position: Vector2.zero(),
);
final rightFlipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ready(); await game.ready();
await game.ensureAddAll([leftFlipper, rightFlipper]); await game.ensureAddAll([leftFlipper, rightFlipper]);
@ -129,10 +38,17 @@ void main() {
group('constructor', () { group('constructor', () {
test('sets BoardSide', () { test('sets BoardSide', () {
final leftFlipper = Flipper.left(position: Vector2.zero()); final leftFlipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
expect(leftFlipper.side, equals(leftFlipper.side)); expect(leftFlipper.side, equals(leftFlipper.side));
final rightFlipper = Flipper.right(position: Vector2.zero()); final rightFlipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
expect(rightFlipper.side, equals(rightFlipper.side)); expect(rightFlipper.side, equals(rightFlipper.side));
}); });
}); });
@ -142,7 +58,10 @@ void main() {
'positions correctly', 'positions correctly',
(game) async { (game) async {
final position = Vector2.all(10); final position = Vector2.all(10);
final flipper = Flipper.left(position: position); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: position,
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
game.contains(flipper); game.contains(flipper);
@ -153,7 +72,10 @@ void main() {
flameTester.test( flameTester.test(
'is dynamic', 'is dynamic',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
expect(flipper.body.bodyType, equals(BodyType.dynamic)); expect(flipper.body.bodyType, equals(BodyType.dynamic));
@ -163,7 +85,10 @@ void main() {
flameTester.test( flameTester.test(
'ignores gravity', 'ignores gravity',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
expect(flipper.body.gravityScale, isZero); expect(flipper.body.gravityScale, isZero);
@ -173,7 +98,10 @@ void main() {
flameTester.test( flameTester.test(
'has greater mass than Ball', 'has greater mass than Ball',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
final ball = Ball(position: Vector2.zero()); final ball = Ball(position: Vector2.zero());
await game.ready(); await game.ready();
@ -191,7 +119,10 @@ void main() {
flameTester.test( flameTester.test(
'has three', 'has three',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
expect(flipper.body.fixtures.length, equals(3)); expect(flipper.body.fixtures.length, equals(3));
@ -201,7 +132,10 @@ void main() {
flameTester.test( flameTester.test(
'has density', 'has density',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final fixtures = flipper.body.fixtures; final fixtures = flipper.body.fixtures;
@ -229,7 +163,10 @@ void main() {
late Flipper flipper; late Flipper flipper;
setUp(() { setUp(() {
flipper = Flipper.left(position: Vector2.zero()); flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
}); });
testRawKeyDownEvents(leftKeys, (event) { testRawKeyDownEvents(leftKeys, (event) {
@ -293,7 +230,10 @@ void main() {
late Flipper flipper; late Flipper flipper;
setUp(() { setUp(() {
flipper = Flipper.right(position: Vector2.zero()); flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
}); });
testRawKeyDownEvents(rightKeys, (event) { testRawKeyDownEvents(rightKeys, (event) {
@ -360,7 +300,10 @@ void main() {
flameTester.test( flameTester.test(
'position is at the left of the left Flipper', 'position is at the left of the left Flipper',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);
@ -373,7 +316,10 @@ void main() {
flameTester.test( flameTester.test(
'position is at the right of the right Flipper', 'position is at the right of the right Flipper',
(game) async { (game) async {
final flipper = Flipper.right(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);
@ -389,7 +335,10 @@ void main() {
flameTester.test( flameTester.test(
'limits enabled', 'limits enabled',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);
@ -408,7 +357,10 @@ void main() {
flameTester.test( flameTester.test(
'when Flipper is left', 'when Flipper is left',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);
@ -426,7 +378,10 @@ void main() {
flameTester.test( flameTester.test(
'when Flipper is right', 'when Flipper is right',
(game) async { (game) async {
final flipper = Flipper.right(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);
@ -449,7 +404,10 @@ void main() {
flameTester.test( flameTester.test(
'when Flipper is left', 'when Flipper is left',
(game) async { (game) async {
final flipper = Flipper.left(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);
@ -473,7 +431,10 @@ void main() {
flameTester.test( flameTester.test(
'when Flipper is right', 'when Flipper is right',
(game) async { (game) async {
final flipper = Flipper.right(position: Vector2.zero()); final flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ensureAdd(flipper); await game.ensureAdd(flipper);
final flipperAnchor = FlipperAnchor(flipper: flipper); final flipperAnchor = FlipperAnchor(flipper: flipper);

@ -54,22 +54,13 @@ void main() {
}, },
); );
flameTester.test('has only one FlipperGroup', (game) async { flameTester.test('has only one BottomGroup', (game) async {
await game.ready(); await game.ready();
expect( expect(
game.children.whereType<FlipperGroup>().length, game.children.whereType<BottomGroup>().length,
equals(1), equals(1),
); );
}); });
flameTester.test(
'has two Baseboards',
(game) async {
await game.ready();
final baseboards = game.children.whereType<Baseboard>();
expect(baseboards.length, 2);
},
);
}); });
debugModeFlameTester.test('adds a ball on tap up', (game) async { debugModeFlameTester.test('adds a ball on tap up', (game) async {

@ -1,3 +1,4 @@
import 'package:flame/components.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_theme/pinball_theme.dart'; import 'package:pinball_theme/pinball_theme.dart';
@ -20,3 +21,41 @@ extension DebugPinballGameTest on DebugPinballGame {
), ),
); );
} }
extension ComponentX on Component {
T findNestedChild<T extends Component>({
bool Function(T)? condition,
}) {
T? nestedChild;
propagateToChildren<T>((child) {
final foundChild = (condition ?? (_) => true)(child);
if (foundChild) {
nestedChild = child;
}
return !foundChild;
});
if (nestedChild == null) {
throw Exception('No child of type $T found.');
} else {
return nestedChild!;
}
}
List<T> findNestedChildren<T extends Component>({
bool Function(T)? condition,
}) {
final nestedChildren = <T>[];
propagateToChildren<T>((child) {
final foundChild = (condition ?? (_) => true)(child);
if (foundChild) {
nestedChildren.add(child);
}
return true;
});
return nestedChildren;
}
}

Loading…
Cancel
Save