feat: implemented `InitialPosition` on `BodyComponent`s (#50)

* feat: made Baseboard use InitialPosition

* feat: made Plunger use InitialPosition

* feat: made SlingShot use InitialPosition

* fix: fixed plunger not initialised

* feat: made RoundBumper use InitialPosition

* feat: made Pathway use InitialPosition

* feat: made JointAnchor use InitialPosition

* feat: made BonusWord use InitialPosition

* feat: changed override to onLoad

* feat: made Flipper use InitialPosition

* feat: made Ball use InitialPosition

* feat: made InitialPosition position the body

* feat: included default value

* feat: removed unnecessary positioning

* refactor: removed old test

* refactor: removed unnecessary tests

* refactor: improved assertion message

Co-authored-by: Erick <erickzanardoo@gmail.com>

Co-authored-by: Erick <erickzanardoo@gmail.com>
pull/53/head
Alejandro Santiago 2 years ago committed by GitHub
parent 401244a8c0
commit 0dc8851e3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,14 +6,9 @@ import 'package:pinball/game/game.dart';
/// A solid, [BodyType.dynamic] sphere that rolls and bounces along the
/// [PinballGame].
/// {@endtemplate}
class Ball extends BodyComponent<PinballGame> {
class Ball extends BodyComponent<PinballGame> with InitialPosition {
/// {@macro ball}
Ball({
required Vector2 position,
}) : _position = position;
/// The initial position of the [Ball] body.
final Vector2 _position;
Ball();
/// The size of the [Ball]
final Vector2 size = Vector2.all(2);
@ -45,7 +40,6 @@ class Ball extends BodyComponent<PinballGame> {
final bodyDef = BodyDef()
..userData = this
..position = Vector2(_position.x, _position.y + size.y)
..type = BodyType.dynamic;
return world.createBody(bodyDef)..createFixture(fixtureDef);

@ -6,13 +6,11 @@ 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 {
class Baseboard extends BodyComponent with InitialPosition {
/// {@macro baseboard}
Baseboard({
required BoardSide side,
required Vector2 position,
}) : _side = side,
_position = position;
}) : _side = side;
/// The width of the [Baseboard].
static const width = 10.0;
@ -20,9 +18,6 @@ class Baseboard extends BodyComponent {
/// 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;
@ -63,7 +58,6 @@ class Baseboard extends BodyComponent {
const angle = math.pi / 7;
final bodyDef = BodyDef()
..position = _position
..type = BodyType.static
..angle = _side.isLeft ? -angle : angle;

@ -59,24 +59,20 @@ class _BottomGroupSide extends Component {
final flipper = Flipper.fromSide(
side: _side,
position: _position,
);
final baseboard = Baseboard(
side: _side,
position: _position +
)..initialPosition = _position;
final baseboard = Baseboard(side: _side)
..initialPosition = _position +
Vector2(
(Flipper.width * direction) - direction,
Flipper.height,
),
);
);
final slingShot = SlingShot(
side: _side,
position: _position +
Vector2(
(Flipper.width) * direction,
Flipper.height + SlingShot.size.y,
),
);
)..initialPosition = _position +
Vector2(
(Flipper.width) * direction,
Flipper.height + SlingShot.size.y,
);
await addAll([flipper, baseboard, slingShot]);
}

@ -74,10 +74,9 @@ class BonusWord extends Component with BlocComponent<GameBloc, GameState> {
unawaited(
add(
BonusLetter(
position: _position - Vector2(16 - (i * 6), -30),
letter: letters[i],
index: i,
),
)..initialPosition = _position - Vector2(16 - (i * 6), -30),
),
);
}
@ -89,14 +88,12 @@ class BonusWord extends Component with BlocComponent<GameBloc, GameState> {
/// which will activate its letter after contact with a [Ball].
/// {@endtemplate}
class BonusLetter extends BodyComponent<PinballGame>
with BlocComponent<GameBloc, GameState> {
with BlocComponent<GameBloc, GameState>, InitialPosition {
/// {@macro bonus_letter}
BonusLetter({
required Vector2 position,
required String letter,
required int index,
}) : _position = position,
_letter = letter,
}) : _letter = letter,
_index = index {
paint = Paint()..color = _disableColor;
}
@ -107,7 +104,6 @@ class BonusLetter extends BodyComponent<PinballGame>
static const _activeColor = Colors.green;
static const _disableColor = Colors.red;
final Vector2 _position;
final String _letter;
final int _index;
@ -134,7 +130,6 @@ class BonusLetter extends BodyComponent<PinballGame>
final bodyDef = BodyDef()
..userData = this
..position = _position
..type = BodyType.static;
return world.createBody(bodyDef)..createFixture(fixtureDef);

@ -13,19 +13,15 @@ import 'package:pinball/game/game.dart';
///
/// [Flipper] can be controlled by the player in an arc motion.
/// {@endtemplate flipper}
class Flipper extends BodyComponent with KeyboardHandler {
class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
/// {@macro flipper}
Flipper._({
required Vector2 position,
required this.side,
required List<LogicalKeyboardKey> keys,
}) : _position = position,
_keys = keys;
}) : _keys = keys;
Flipper._left({
required Vector2 position,
}) : this._(
position: position,
Flipper._left()
: this._(
side: BoardSide.left,
keys: [
LogicalKeyboardKey.arrowLeft,
@ -33,10 +29,8 @@ class Flipper extends BodyComponent with KeyboardHandler {
],
);
Flipper._right({
required Vector2 position,
}) : this._(
position: position,
Flipper._right()
: this._(
side: BoardSide.right,
keys: [
LogicalKeyboardKey.arrowRight,
@ -50,13 +44,12 @@ class Flipper extends BodyComponent with KeyboardHandler {
/// 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);
return Flipper._left();
case BoardSide.right:
return Flipper._right(position: position);
return Flipper._right();
}
}
@ -82,9 +75,6 @@ class Flipper extends BodyComponent with KeyboardHandler {
/// whereas a [Flipper] with [BoardSide.right] has a clockwise arc motion.
final BoardSide side;
/// The initial position of the [Flipper] body.
final Vector2 _position;
/// The [LogicalKeyboardKey]s that will control the [Flipper].
///
/// [onKeyEvent] method listens to when one of these keys is pressed.
@ -200,9 +190,7 @@ class Flipper extends BodyComponent with KeyboardHandler {
Body createBody() {
final bodyDef = BodyDef()
..gravityScale = 0
..type = BodyType.dynamic
..position = _position;
..type = BodyType.dynamic;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
@ -238,14 +226,14 @@ class FlipperAnchor extends JointAnchor {
/// {@macro flipper_anchor}
FlipperAnchor({
required Flipper flipper,
}) : super(
position: Vector2(
flipper.side.isLeft
? flipper.body.position.x - Flipper.width / 2
: flipper.body.position.x + Flipper.width / 2,
flipper.body.position.y,
),
);
}) {
initialPosition = Vector2(
flipper.side.isLeft
? flipper.body.position.x - Flipper.width / 2
: flipper.body.position.x + Flipper.width / 2,
flipper.body.position.y,
);
}
}
/// {@template flipper_anchor_revolute_joint_def}

@ -2,16 +2,28 @@ import 'package:flame_forge2d/flame_forge2d.dart';
/// Forces a given [BodyComponent] to position their [body] to an
/// [initialPosition].
///
/// Note: If the [initialPosition] is set after the [BodyComponent] has been
/// loaded it will have no effect; defaulting to [Vector2.zero].
mixin InitialPosition<T extends Forge2DGame> on BodyComponent<T> {
/// The initial position of the [body].
late final Vector2 initialPosition;
final Vector2 _initialPosition = Vector2.zero();
@override
void onMount() {
super.onMount();
set initialPosition(Vector2 value) {
assert(
body.position == initialPosition,
'Body position is not equal to initial position.',
!isLoaded,
'Cannot set initialPosition after component has already loaded.',
);
if (value == initialPosition) return;
_initialPosition.setFrom(value);
}
/// The initial position of the [body].
Vector2 get initialPosition => _initialPosition;
@override
Future<void> onLoad() async {
await super.onLoad();
body.position.setFrom(initialPosition);
}
}

@ -1,11 +1,12 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/game.dart';
/// {@template joint_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].
/// It is recommended to use [JointAnchor.body.position] to position the anchor
/// point when initializing a [JointDef].
///
/// ```dart
/// initialize(
@ -15,18 +16,12 @@ import 'package:flame_forge2d/flame_forge2d.dart';
/// );
/// ```
/// {@endtemplate}
class JointAnchor extends BodyComponent {
class JointAnchor extends BodyComponent with InitialPosition {
/// {@macro joint_anchor}
JointAnchor({
required Vector2 position,
}) : _position = position;
final Vector2 _position;
JointAnchor();
@override
Body createBody() {
final bodyDef = BodyDef()..position = _position;
return world.createBody(bodyDef);
return world.createBody(BodyDef());
}
}

@ -2,20 +2,19 @@ import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:geometry/geometry.dart';
import 'package:pinball/game/game.dart';
/// {@template pathway}
/// [Pathway] creates lines of various shapes.
///
/// [BodyComponent]s such as a Ball can collide and move along a [Pathway].
/// {@endtemplate}
class Pathway extends BodyComponent {
class Pathway extends BodyComponent with InitialPosition {
Pathway._({
// TODO(ruialonso): remove color when assets added.
Color? color,
required Vector2 position,
required List<List<Vector2>> paths,
}) : _position = position,
_paths = paths {
}) : _paths = paths {
paint = Paint()
..color = color ?? const Color.fromARGB(0, 0, 0, 0)
..style = PaintingStyle.stroke;
@ -23,14 +22,12 @@ class Pathway extends BodyComponent {
/// Creates a uniform unidirectional (straight) [Pathway].
///
/// Does so with two [ChainShape] separated by a [width]. Placed
/// at a [position] between [start] and [end] points. Can
/// Does so with two [ChainShape] separated by a [width]. Can
/// be rotated by a given [rotation] in radians.
///
/// If [singleWall] is true, just one [ChainShape] is created.
factory Pathway.straight({
Color? color,
required Vector2 position,
required Vector2 start,
required Vector2 end,
required double width,
@ -56,28 +53,25 @@ class Pathway extends BodyComponent {
return Pathway._(
color: color,
position: position,
paths: paths,
);
}
/// Creates an arc [Pathway].
///
/// The [angle], in radians, specifies the size of the arc. For example, 2*pi
/// returns a complete circumference and minor angles a semi circumference.
///
/// The center of the arc is placed at [position].
/// The [angle], in radians, specifies the size of the arc. For example, two
/// pi returns a complete circumference.
///
/// Does so with two [ChainShape] separated by a [width]. Which can be
/// rotated by a given [rotation] in radians.
///
/// The outer radius is specified by [radius], whilst the inner one is
/// equivalent to [radius] - [width].
/// equivalent to the [radius] minus the [width].
///
/// If [singleWall] is true, just one [ChainShape] is created.
factory Pathway.arc({
Color? color,
required Vector2 position,
required Vector2 center,
required double width,
required double radius,
required double angle,
@ -88,7 +82,7 @@ class Pathway extends BodyComponent {
// TODO(ruialonso): Refactor repetitive logic
final outerWall = calculateArc(
center: position,
center: center,
radius: radius,
angle: angle,
offsetAngle: rotation,
@ -97,7 +91,7 @@ class Pathway extends BodyComponent {
if (!singleWall) {
final innerWall = calculateArc(
center: position,
center: center,
radius: radius - width,
angle: angle,
offsetAngle: rotation,
@ -107,7 +101,6 @@ class Pathway extends BodyComponent {
return Pathway._(
color: color,
position: position,
paths: paths,
);
}
@ -123,7 +116,6 @@ class Pathway extends BodyComponent {
/// If [singleWall] is true, just one [ChainShape] is created.
factory Pathway.bezierCurve({
Color? color,
required Vector2 position,
required List<Vector2> controlPoints,
required double width,
double rotation = 0,
@ -148,20 +140,15 @@ class Pathway extends BodyComponent {
return Pathway._(
color: color,
position: position,
paths: paths,
);
}
final Vector2 _position;
final List<List<Vector2>> _paths;
@override
Body createBody() {
final bodyDef = BodyDef()
..type = BodyType.static
..position = _position;
final bodyDef = BodyDef()..type = BodyType.static;
final body = world.createBody(bodyDef);
for (final path in _paths) {
final chain = ChainShape()

@ -9,15 +9,11 @@ import 'package:pinball/game/game.dart';
///
/// [Plunger] ignores gravity so the player controls its downward [_pull].
/// {@endtemplate}
class Plunger extends BodyComponent with KeyboardHandler {
class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
/// {@macro plunger}
Plunger({
required Vector2 position,
required this.compressionDistance,
}) : _position = position;
/// The initial position of the [Plunger] body.
final Vector2 _position;
});
/// Distance the plunger can lower.
final double compressionDistance;
@ -30,7 +26,6 @@ class Plunger extends BodyComponent with KeyboardHandler {
final bodyDef = BodyDef()
..userData = this
..position = _position
..type = BodyType.dynamic
..gravityScale = 0;
@ -45,9 +40,9 @@ class Plunger extends BodyComponent with KeyboardHandler {
/// Set an upward velocity on the [Plunger].
///
/// The velocity's magnitude depends on how far the [Plunger] has been pulled
/// from its original [_position].
/// from its original [initialPosition].
void _release() {
final velocity = (_position.y - body.position.y) * 9;
final velocity = (initialPosition.y - body.position.y) * 9;
body.linearVelocity = Vector2(0, velocity);
}
@ -102,12 +97,12 @@ class PlungerAnchor extends JointAnchor {
/// {@macro plunger_anchor}
PlungerAnchor({
required Plunger plunger,
}) : super(
position: Vector2(
plunger.body.position.x,
plunger.body.position.y - plunger.compressionDistance,
),
);
}) {
initialPosition = Vector2(
plunger.body.position.x,
plunger.body.position.y - plunger.compressionDistance,
);
}
}
/// {@template plunger_anchor_prismatic_joint_def}

@ -4,19 +4,14 @@ import 'package:pinball/game/game.dart';
/// {@template round_bumper}
/// Circular body that repels a [Ball] on contact, increasing the score.
/// {@endtemplate}
class RoundBumper extends BodyComponent with ScorePoints {
class RoundBumper extends BodyComponent with ScorePoints, InitialPosition {
/// {@macro round_bumper}
RoundBumper({
required Vector2 position,
required double radius,
required int points,
}) : _position = position,
_radius = radius,
}) : _radius = radius,
_points = points;
/// The position of the [RoundBumper] body.
final Vector2 _position;
/// The radius of the [RoundBumper].
final double _radius;
@ -32,9 +27,7 @@ class RoundBumper extends BodyComponent with ScorePoints {
final fixtureDef = FixtureDef(shape)..restitution = 1;
final bodyDef = BodyDef()
..position = _position
..type = BodyType.static;
final bodyDef = BodyDef()..type = BodyType.static;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}

@ -10,22 +10,17 @@ import 'package:pinball/game/game.dart';
///
/// [SlingShot]s are usually positioned above each [Flipper].
/// {@endtemplate sling_shot}
class SlingShot extends BodyComponent {
class SlingShot extends BodyComponent with InitialPosition {
/// {@macro sling_shot}
SlingShot({
required Vector2 position,
required BoardSide side,
}) : _position = position,
_side = side {
}) : _side = side {
// TODO(alestiago): Use sprite instead of color when provided.
paint = Paint()
..color = const Color(0xFF00FF00)
..style = PaintingStyle.fill;
}
/// The initial position of the [SlingShot] body.
final Vector2 _position;
/// Whether the [SlingShot] is on the left or right side of the board.
///
/// A [SlingShot] with [BoardSide.left] propels the [Ball] to the right,
@ -88,8 +83,7 @@ class SlingShot extends BodyComponent {
@override
Body createBody() {
final bodyDef = BodyDef()..position = _position;
final body = world.createBody(bodyDef);
final body = world.createBody(BodyDef());
_createFixtureDefs().forEach(body.createFixture);
return body;

@ -78,7 +78,11 @@ class PinballGame extends Forge2DGame
}
void spawnBall() {
add(Ball(position: plunger.body.position));
final ball = Ball();
add(
ball
..initialPosition = plunger.body.position + Vector2(0, ball.size.y / 2),
);
}
void _addContactCallbacks() {
@ -93,19 +97,17 @@ class PinballGame extends Forge2DGame
}
Future<void> _addPlunger() async {
final compressionDistance = camera.viewport.effectiveSize.y / 12;
await add(
plunger = Plunger(
position: screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 1.035,
camera.viewport.effectiveSize.y - compressionDistance,
),
),
compressionDistance: compressionDistance,
plunger = Plunger(
compressionDistance: camera.viewport.effectiveSize.y / 12,
);
plunger.initialPosition = screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 1.035,
camera.viewport.effectiveSize.y - plunger.compressionDistance,
),
);
await add(plunger);
}
}
@ -114,6 +116,8 @@ class DebugPinballGame extends PinballGame with TapDetector {
@override
void onTapUp(TapUpInfo info) {
add(Ball(position: info.eventPosition.game));
add(
Ball()..initialPosition = info.eventPosition.game,
);
}
}

@ -17,7 +17,7 @@ void main() {
flameTester.test(
'loads correctly',
(game) async {
final ball = Ball(position: Vector2.zero());
final ball = Ball();
await game.ready();
await game.ensureAdd(ball);
@ -26,26 +26,10 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final ball = Ball(position: position);
await game.ensureAdd(ball);
game.contains(ball);
final expectedPosition = Vector2(
position.x,
position.y + ball.size.y,
);
expect(ball.body.position, equals(expectedPosition));
},
);
flameTester.test(
'is dynamic',
(game) async {
final ball = Ball(position: Vector2.zero());
final ball = Ball();
await game.ensureAdd(ball);
expect(ball.body.bodyType, equals(BodyType.dynamic));
@ -57,7 +41,7 @@ void main() {
flameTester.test(
'exists',
(game) async {
final ball = Ball(position: Vector2.zero());
final ball = Ball();
await game.ensureAdd(ball);
expect(ball.body.fixtures[0], isA<Fixture>());
@ -67,7 +51,7 @@ void main() {
flameTester.test(
'is dense',
(game) async {
final ball = Ball(position: Vector2.zero());
final ball = Ball();
await game.ensureAdd(ball);
final fixture = ball.body.fixtures[0];
@ -78,7 +62,7 @@ void main() {
flameTester.test(
'shape is circular',
(game) async {
final ball = Ball(position: Vector2.zero());
final ball = Ball();
await game.ensureAdd(ball);
final fixture = ball.body.fixtures[0];

@ -15,13 +15,12 @@ void main() {
(game) async {
await game.ready();
final leftBaseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.left,
);
final rightBaseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.right,
);
await game.ensureAddAll([leftBaseboard, rightBaseboard]);
expect(game.contains(leftBaseboard), isTrue);
@ -30,28 +29,13 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final baseboard = Baseboard(
position: position,
side: BoardSide.left,
);
await game.ensureAdd(baseboard);
game.contains(baseboard);
expect(baseboard.body.position, position);
},
);
flameTester.test(
'is static',
(game) async {
final baseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(baseboard);
expect(baseboard.body.bodyType, equals(BodyType.static));
@ -62,11 +46,9 @@ void main() {
'is at an angle',
(game) async {
final leftBaseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.left,
);
final rightBaseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.right,
);
await game.ensureAddAll([leftBaseboard, rightBaseboard]);
@ -82,7 +64,6 @@ void main() {
'has three',
(game) async {
final baseboard = Baseboard(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(baseboard);

@ -123,7 +123,6 @@ void main() {
'loads correctly',
(game) async {
final bonusLetter = BonusLetter(
position: Vector2.zero(),
letter: 'G',
index: 0,
);
@ -135,27 +134,10 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final bonusLetter = BonusLetter(
position: position,
letter: 'G',
index: 0,
);
await game.ensureAdd(bonusLetter);
game.contains(bonusLetter);
expect(bonusLetter.body.position, position);
},
);
flameTester.test(
'is static',
(game) async {
final bonusLetter = BonusLetter(
position: Vector2.zero(),
letter: 'G',
index: 0,
);
@ -171,7 +153,6 @@ void main() {
'exists',
(game) async {
final bonusLetter = BonusLetter(
position: Vector2.zero(),
letter: 'G',
index: 0,
);
@ -185,7 +166,6 @@ void main() {
'is sensor',
(game) async {
final bonusLetter = BonusLetter(
position: Vector2.zero(),
letter: 'G',
index: 0,
);
@ -200,7 +180,6 @@ void main() {
'shape is circular',
(game) async {
final bonusLetter = BonusLetter(
position: Vector2.zero(),
letter: 'G',
index: 0,
);

@ -22,11 +22,9 @@ void main() {
(game) async {
final leftFlipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
final rightFlipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ready();
await game.ensureAddAll([leftFlipper, rightFlipper]);
@ -40,41 +38,23 @@ void main() {
test('sets BoardSide', () {
final leftFlipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
expect(leftFlipper.side, equals(leftFlipper.side));
final rightFlipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
expect(rightFlipper.side, equals(rightFlipper.side));
});
});
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: position,
);
await game.ensureAdd(flipper);
game.contains(flipper);
expect(flipper.body.position, position);
},
);
flameTester.test(
'is dynamic',
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -87,7 +67,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -100,9 +79,8 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
final ball = Ball(position: Vector2.zero());
final ball = Ball();
await game.ready();
await game.ensureAddAll([flipper, ball]);
@ -121,7 +99,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -134,7 +111,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -165,7 +141,6 @@ void main() {
setUp(() {
flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
});
@ -232,7 +207,6 @@ void main() {
setUp(() {
flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
});
@ -302,7 +276,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -318,7 +291,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -337,7 +309,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -359,7 +330,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -380,7 +350,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -406,7 +375,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.left,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);
@ -433,7 +401,6 @@ void main() {
(game) async {
final flipper = Flipper.fromSide(
side: BoardSide.right,
position: Vector2.zero(),
);
await game.ensureAdd(flipper);

@ -12,13 +12,6 @@ class TestBodyComponent extends BodyComponent with InitialPosition {
}
}
class TestPositionedBodyComponent extends BodyComponent with InitialPosition {
@override
Body createBody() {
return world.createBody(BodyDef()..position = initialPosition);
}
}
void main() {
final flameTester = FlameTester(Forge2DGame.new);
group('InitialPosition', () {
@ -27,37 +20,36 @@ void main() {
expect(component.initialPosition, Vector2(1, 2));
});
test('can only be set once', () {
final component = TestBodyComponent()..initialPosition = Vector2(1, 2);
expect(
() => component.initialPosition = Vector2(3, 4),
throwsA(isA<Error>()),
);
});
flameTester.test(
'returns normally '
'when the body sets the position to initial position',
'positions correctly',
(game) async {
final component = TestPositionedBodyComponent()
..initialPosition = Vector2.zero();
final position = Vector2.all(10);
final component = TestBodyComponent()..initialPosition = position;
await game.ensureAdd(component);
expect(component.body.position, equals(position));
},
);
await expectLater(
() async => game.ensureAdd(component),
returnsNormally,
);
flameTester.test(
'deafaults to zero '
'when no initialPosition is given',
(game) async {
final component = TestBodyComponent();
await game.ensureAdd(component);
expect(component.body.position, equals(Vector2.zero()));
},
);
flameTester.test(
'throws AssertionError '
'when not setting initialPosition to body',
'setting throws AssertionError '
'when component has loaded',
(game) async {
final component = TestBodyComponent()..initialPosition = Vector2.zero();
final component = TestBodyComponent();
await game.ensureAdd(component);
await expectLater(
() async => game.ensureAdd(component),
expect(component.isLoaded, isTrue);
expect(
() => component.initialPosition = Vector2.all(4),
throwsAssertionError,
);
},

@ -13,7 +13,7 @@ void main() {
flameTester.test(
'loads correctly',
(game) async {
final anchor = JointAnchor(position: Vector2.zero());
final anchor = JointAnchor();
await game.ready();
await game.ensureAdd(anchor);
@ -22,24 +22,11 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
await game.ready();
final position = Vector2.all(10);
final anchor = JointAnchor(position: position);
await game.ensureAdd(anchor);
game.contains(anchor);
expect(anchor.body.position, position);
},
);
flameTester.test(
'is static',
(game) async {
await game.ready();
final anchor = JointAnchor(position: Vector2.zero());
final anchor = JointAnchor();
await game.ensureAdd(anchor);
expect(anchor.body.bodyType, equals(BodyType.static));
@ -51,7 +38,7 @@ void main() {
flameTester.test(
'has none',
(game) async {
final anchor = JointAnchor(position: Vector2.zero());
final anchor = JointAnchor();
await game.ensureAdd(anchor);
expect(anchor.body.fixtures, isEmpty);

@ -20,7 +20,6 @@ void main() {
(game) async {
await game.ready();
final pathway = Pathway.straight(
position: Vector2.zero(),
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
@ -44,7 +43,6 @@ void main() {
final pathway = Pathway.straight(
color: defaultColor,
position: Vector2.zero(),
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
@ -63,7 +61,6 @@ void main() {
(game) async {
await game.ready();
final pathway = Pathway.straight(
position: Vector2.zero(),
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
@ -75,30 +72,11 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
await game.ready();
final position = Vector2.all(10);
final pathway = Pathway.straight(
position: position,
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
);
await game.ensureAdd(pathway);
game.contains(pathway);
expect(pathway.body.position, position);
},
);
flameTester.test(
'is static',
(game) async {
await game.ready();
final pathway = Pathway.straight(
position: Vector2.zero(),
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
@ -116,7 +94,6 @@ void main() {
(game) async {
await game.ready();
final pathway = Pathway.straight(
position: Vector2.zero(),
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
@ -136,7 +113,6 @@ void main() {
(game) async {
await game.ready();
final pathway = Pathway.straight(
position: Vector2.zero(),
start: Vector2(10, 10),
end: Vector2(20, 20),
width: width,
@ -159,7 +135,7 @@ void main() {
(game) async {
await game.ready();
final pathway = Pathway.arc(
position: Vector2.zero(),
center: Vector2.zero(),
width: width,
radius: 100,
angle: math.pi / 2,
@ -171,30 +147,12 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
await game.ready();
final position = Vector2.all(10);
final pathway = Pathway.arc(
position: position,
width: width,
radius: 100,
angle: math.pi / 2,
);
await game.ensureAdd(pathway);
game.contains(pathway);
expect(pathway.body.position, position);
},
);
flameTester.test(
'is static',
(game) async {
await game.ready();
final pathway = Pathway.arc(
position: Vector2.zero(),
center: Vector2.zero(),
width: width,
radius: 100,
angle: math.pi / 2,
@ -220,7 +178,6 @@ void main() {
(game) async {
await game.ready();
final pathway = Pathway.bezierCurve(
position: Vector2.zero(),
controlPoints: controlPoints,
width: width,
);
@ -231,29 +188,11 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
await game.ready();
final position = Vector2.all(10);
final pathway = Pathway.bezierCurve(
position: position,
controlPoints: controlPoints,
width: width,
);
await game.ensureAdd(pathway);
game.contains(pathway);
expect(pathway.body.position, position);
},
);
flameTester.test(
'is static',
(game) async {
await game.ready();
final pathway = Pathway.bezierCurve(
position: Vector2.zero(),
controlPoints: controlPoints,
width: width,
);

@ -23,7 +23,6 @@ void main() {
(game) async {
await game.ready();
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -33,26 +32,10 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final plunger = Plunger(
position: position,
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
game.contains(plunger);
expect(plunger.body.position, position);
},
);
flameTester.test(
'is dynamic',
(game) async {
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -65,7 +48,6 @@ void main() {
'ignores gravity',
(game) async {
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -80,7 +62,6 @@ void main() {
'exists',
(game) async {
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -93,7 +74,6 @@ void main() {
'shape is a polygon',
(game) async {
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -107,7 +87,6 @@ void main() {
'has density',
(game) async {
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -129,7 +108,6 @@ void main() {
setUp(() {
plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
});
@ -194,7 +172,6 @@ void main() {
'position is a compression distance below the Plunger',
(game) async {
final plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
@ -222,7 +199,6 @@ void main() {
initialState: const GameState.initial(),
);
plunger = Plunger(
position: Vector2.zero(),
compressionDistance: compressionDistance,
);
});

@ -18,7 +18,6 @@ void main() {
(game) async {
await game.ready();
final roundBumper = RoundBumper(
position: Vector2.zero(),
radius: radius,
points: points,
);
@ -32,7 +31,6 @@ void main() {
'has points',
(game) async {
final roundBumper = RoundBumper(
position: Vector2.zero(),
radius: radius,
points: points,
);
@ -43,27 +41,10 @@ void main() {
);
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,
);
@ -79,7 +60,6 @@ void main() {
'exists',
(game) async {
final roundBumper = RoundBumper(
position: Vector2.zero(),
radius: radius,
points: points,
);
@ -93,7 +73,6 @@ void main() {
'has restitution',
(game) async {
final roundBumper = RoundBumper(
position: Vector2.zero(),
radius: radius,
points: points,
);
@ -108,7 +87,6 @@ void main() {
'shape is circular',
(game) async {
final roundBumper = RoundBumper(
position: Vector2.zero(),
radius: radius,
points: points,
);

@ -13,7 +13,6 @@ void main() {
'loads correctly',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -23,25 +22,10 @@ void main() {
);
group('body', () {
flameTester.test(
'positions correctly',
(game) async {
final position = Vector2.all(10);
final slingShot = SlingShot(
position: position,
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
expect(slingShot.body.position, equals(position));
},
);
flameTester.test(
'is static',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -56,7 +40,6 @@ void main() {
'exists',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -69,7 +52,6 @@ void main() {
'shape is triangular',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -85,11 +67,9 @@ void main() {
'when side is left or right',
(game) async {
final leftSlingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
final rightSlingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.right,
);
@ -109,7 +89,6 @@ void main() {
'has no friction',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -125,7 +104,6 @@ void main() {
'exists',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -138,7 +116,6 @@ void main() {
'shape is edge',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -152,7 +129,6 @@ void main() {
'has restitution',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);
@ -166,7 +142,6 @@ void main() {
'has no friction',
(game) async {
final slingShot = SlingShot(
position: Vector2.zero(),
side: BoardSide.left,
);
await game.ensureAdd(slingShot);

Loading…
Cancel
Save