mirror of https://github.com/flutter/pinball.git
refactor: Pathway to Shapes (#87)
* refactor: removed findNested extensions (#77) * refactor: changed Pathway for Shapes * refactor: renamed pathway to shape * refactor: moved shapes to components package * fix: fixed arc radius on shapes * refactor: changed jetpack to shapes * refactor: modified jetpack ramp to use shapes and blueprint * refactor: launcher ramp * test: removed unnecessary tests for ramps * refactor: refactored baseboard with arcshapes * chore: doc refactor * test: coverage tests * refactor: refactored launcher ramp * test: tests for shapes * test: added removed ellipse tests * test: arcshape coverage * test: unnecessary tests removed * chore: params names * chore: modified doc for Layered and added one test for nested * test: changed tests names * test: not layered nested children * refactor: moved static param and made other private on ramps * Update lib/game/components/jetpack_ramp.dart Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * Update lib/game/components/jetpack_ramp.dart Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * Update lib/game/components/launcher_ramp.dart Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * chore: renamed straight path vars * Update packages/pinball_components/lib/src/components/shapes/arc_shape.dart Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * refactor: constructors with rotation instead of separated method * test: refactored tests * refactor: moved rotate to separate method * refactor: rotation on shapes Co-authored-by: RuiAlonso <rui.alonso@verygood.ventures> Co-authored-by: Rui Miguel Alonso <ruiskas@gmail.com> Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>pull/104/head
parent
ce8917e17d
commit
411b489e1e
@ -1,209 +0,0 @@
|
||||
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_components/pinball_components.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 with InitialPosition, Layered {
|
||||
Pathway._({
|
||||
// TODO(ruialonso): remove color when assets added.
|
||||
Color? color,
|
||||
required List<List<Vector2>> paths,
|
||||
}) : _paths = paths {
|
||||
paint = Paint()
|
||||
..color = color ?? const Color.fromARGB(0, 0, 0, 0)
|
||||
..style = PaintingStyle.stroke;
|
||||
}
|
||||
|
||||
/// Creates a uniform unidirectional (straight) [Pathway].
|
||||
///
|
||||
/// 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 start,
|
||||
required Vector2 end,
|
||||
required double width,
|
||||
double rotation = 0,
|
||||
bool singleWall = false,
|
||||
}) {
|
||||
final paths = <List<Vector2>>[];
|
||||
|
||||
// TODO(ruialonso): Refactor repetitive logic
|
||||
final firstWall = [
|
||||
start.clone(),
|
||||
end.clone(),
|
||||
].map((vector) => vector..rotate(rotation)).toList();
|
||||
paths.add(firstWall);
|
||||
|
||||
if (!singleWall) {
|
||||
final secondWall = [
|
||||
start + Vector2(width, 0),
|
||||
end + Vector2(width, 0),
|
||||
].map((vector) => vector..rotate(rotation)).toList();
|
||||
paths.add(secondWall);
|
||||
}
|
||||
|
||||
return Pathway._(
|
||||
color: color,
|
||||
paths: paths,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates an arc [Pathway].
|
||||
///
|
||||
/// 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 the [radius] minus the [width].
|
||||
///
|
||||
/// If [singleWall] is true, just one [ChainShape] is created.
|
||||
factory Pathway.arc({
|
||||
Color? color,
|
||||
required Vector2 center,
|
||||
required double width,
|
||||
required double radius,
|
||||
required double angle,
|
||||
double rotation = 0,
|
||||
bool singleWall = false,
|
||||
}) {
|
||||
final paths = <List<Vector2>>[];
|
||||
|
||||
// TODO(ruialonso): Refactor repetitive logic
|
||||
final outerWall = calculateArc(
|
||||
center: center,
|
||||
radius: radius,
|
||||
angle: angle,
|
||||
offsetAngle: rotation,
|
||||
);
|
||||
paths.add(outerWall);
|
||||
|
||||
if (!singleWall) {
|
||||
final innerWall = calculateArc(
|
||||
center: center,
|
||||
radius: radius - width,
|
||||
angle: angle,
|
||||
offsetAngle: rotation,
|
||||
);
|
||||
paths.add(innerWall);
|
||||
}
|
||||
|
||||
return Pathway._(
|
||||
color: color,
|
||||
paths: paths,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a bezier curve [Pathway].
|
||||
///
|
||||
/// Does so with two [ChainShape] separated by a [width]. Which can be
|
||||
/// rotated by a given [rotation] in radians.
|
||||
///
|
||||
/// First and last [controlPoints] set the beginning and end of the curve,
|
||||
/// inner points between them set its final shape.
|
||||
///
|
||||
/// If [singleWall] is true, just one [ChainShape] is created.
|
||||
factory Pathway.bezierCurve({
|
||||
Color? color,
|
||||
required List<Vector2> controlPoints,
|
||||
required double width,
|
||||
double rotation = 0,
|
||||
bool singleWall = false,
|
||||
}) {
|
||||
final paths = <List<Vector2>>[];
|
||||
|
||||
// TODO(ruialonso): Refactor repetitive logic
|
||||
final firstWall = calculateBezierCurve(controlPoints: controlPoints)
|
||||
.map((vector) => vector..rotate(rotation))
|
||||
.toList();
|
||||
paths.add(firstWall);
|
||||
|
||||
if (!singleWall) {
|
||||
final secondWall = calculateBezierCurve(
|
||||
controlPoints: controlPoints
|
||||
.map((vector) => vector + Vector2(width, -width))
|
||||
.toList(),
|
||||
).map((vector) => vector..rotate(rotation)).toList();
|
||||
paths.add(secondWall);
|
||||
}
|
||||
|
||||
return Pathway._(
|
||||
color: color,
|
||||
paths: paths,
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates an ellipse [Pathway].
|
||||
///
|
||||
/// Does so with two [ChainShape]s separated by a [width]. Can
|
||||
/// be rotated by a given [rotation] in radians.
|
||||
///
|
||||
/// If [singleWall] is true, just one [ChainShape] is created.
|
||||
factory Pathway.ellipse({
|
||||
Color? color,
|
||||
required Vector2 center,
|
||||
required double width,
|
||||
required double majorRadius,
|
||||
required double minorRadius,
|
||||
double rotation = 0,
|
||||
bool singleWall = false,
|
||||
}) {
|
||||
final paths = <List<Vector2>>[];
|
||||
|
||||
// TODO(ruialonso): Refactor repetitive logic
|
||||
final outerWall = calculateEllipse(
|
||||
center: center,
|
||||
majorRadius: majorRadius,
|
||||
minorRadius: minorRadius,
|
||||
).map((vector) => vector..rotate(rotation)).toList();
|
||||
paths.add(outerWall);
|
||||
|
||||
if (!singleWall) {
|
||||
final innerWall = calculateEllipse(
|
||||
center: center,
|
||||
majorRadius: majorRadius - width,
|
||||
minorRadius: minorRadius - width,
|
||||
).map((vector) => vector..rotate(rotation)).toList();
|
||||
paths.add(innerWall);
|
||||
}
|
||||
|
||||
return Pathway._(
|
||||
color: color,
|
||||
paths: paths,
|
||||
);
|
||||
}
|
||||
|
||||
final List<List<Vector2>> _paths;
|
||||
|
||||
/// Constructs different [ChainShape]s to form the [Pathway] shape.
|
||||
List<FixtureDef> createFixtureDefs() {
|
||||
final fixturesDef = <FixtureDef>[];
|
||||
|
||||
for (final path in _paths) {
|
||||
final chain = ChainShape()..createChain(path);
|
||||
fixturesDef.add(FixtureDef(chain));
|
||||
}
|
||||
|
||||
return fixturesDef;
|
||||
}
|
||||
|
||||
@override
|
||||
Body createBody() {
|
||||
final bodyDef = BodyDef()..position = initialPosition;
|
||||
final body = world.createBody(bodyDef);
|
||||
createFixtureDefs().forEach(body.createFixture);
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
// ignore_for_file: public_member_api_docs
|
||||
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:geometry/geometry.dart';
|
||||
|
||||
/// {@template arc_shape}
|
||||
/// Creates an arc.
|
||||
/// {@endtemplate}
|
||||
class ArcShape extends ChainShape {
|
||||
/// {@macro arc_shape}
|
||||
ArcShape({
|
||||
required this.center,
|
||||
required this.arcRadius,
|
||||
required this.angle,
|
||||
this.rotation = 0,
|
||||
}) {
|
||||
createChain(
|
||||
calculateArc(
|
||||
center: center,
|
||||
radius: arcRadius,
|
||||
angle: angle,
|
||||
offsetAngle: rotation,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// The center of the arc.
|
||||
final Vector2 center;
|
||||
|
||||
/// The radius of the arc.
|
||||
// TODO(alestiago): Check if modifying the parent radius makes sense.
|
||||
final double arcRadius;
|
||||
|
||||
/// Specifies the size of the arc, in radians.
|
||||
///
|
||||
/// For example, two pi returns a complete circumference.
|
||||
final double angle;
|
||||
|
||||
/// Angle in radians to rotate the arc around its [center].
|
||||
final double rotation;
|
||||
|
||||
ArcShape copyWith({
|
||||
Vector2? center,
|
||||
double? arcRadius,
|
||||
double? angle,
|
||||
double? rotation,
|
||||
}) =>
|
||||
ArcShape(
|
||||
center: center ?? this.center,
|
||||
arcRadius: arcRadius ?? this.arcRadius,
|
||||
angle: angle ?? this.angle,
|
||||
rotation: rotation ?? this.rotation,
|
||||
);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// ignore_for_file: public_member_api_docs
|
||||
|
||||
import 'package:flame/extensions.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:geometry/geometry.dart';
|
||||
|
||||
/// {@template bezier_curve_shape}
|
||||
/// Creates a bezier curve.
|
||||
/// {@endtemplate}
|
||||
class BezierCurveShape extends ChainShape {
|
||||
/// {@macro bezier_curve_shape}
|
||||
BezierCurveShape({
|
||||
required this.controlPoints,
|
||||
}) {
|
||||
createChain(calculateBezierCurve(controlPoints: controlPoints));
|
||||
}
|
||||
|
||||
/// Specifies the control points of the curve.
|
||||
///
|
||||
/// First and last [controlPoints] set the beginning and end of the curve,
|
||||
/// inner points between them set its final shape.
|
||||
final List<Vector2> controlPoints;
|
||||
|
||||
/// Rotates the bezier curve by a given [angle] in radians.
|
||||
void rotate(double angle) {
|
||||
vertices.map((vector) => vector..rotate(angle)).toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// ignore_for_file: public_member_api_docs
|
||||
|
||||
import 'package:flame/extensions.dart';
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:geometry/geometry.dart';
|
||||
|
||||
/// {@template ellipse_shape}
|
||||
/// Creates an ellipse.
|
||||
/// {@endtemplate}
|
||||
class EllipseShape extends ChainShape {
|
||||
/// {@macro ellipse_shape}
|
||||
EllipseShape({
|
||||
required this.center,
|
||||
required this.majorRadius,
|
||||
required this.minorRadius,
|
||||
}) {
|
||||
createChain(
|
||||
calculateEllipse(
|
||||
center: center,
|
||||
majorRadius: majorRadius,
|
||||
minorRadius: minorRadius,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// The top left corner of the ellipse.
|
||||
///
|
||||
/// Where the initial painting begins.
|
||||
// TODO(ruialonso): Change to use appropiate center.
|
||||
final Vector2 center;
|
||||
|
||||
/// Major radius is specified by [majorRadius].
|
||||
final double majorRadius;
|
||||
|
||||
/// Minor radius is specified by [minorRadius].
|
||||
final double minorRadius;
|
||||
|
||||
/// Rotates the ellipse by a given [angle] in radians.
|
||||
void rotate(double angle) {
|
||||
vertices.map((vector) => vector..rotate(angle)).toList();
|
||||
}
|
||||
|
||||
EllipseShape copyWith({
|
||||
Vector2? center,
|
||||
double? majorRadius,
|
||||
double? minorRadius,
|
||||
}) =>
|
||||
EllipseShape(
|
||||
center: center ?? this.center,
|
||||
majorRadius: majorRadius ?? this.majorRadius,
|
||||
minorRadius: minorRadius ?? this.minorRadius,
|
||||
);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
export 'arc_shape.dart';
|
||||
export 'bezier_curve_shape.dart';
|
||||
export 'ellipse_shape.dart';
|
@ -0,0 +1,66 @@
|
||||
import 'dart:math' as math;
|
||||
import 'package:flame/extensions.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pinball_components/src/components/components.dart';
|
||||
|
||||
void main() {
|
||||
group('ArcShape', () {
|
||||
test('can be instantiated', () {
|
||||
expect(
|
||||
ArcShape(
|
||||
center: Vector2.zero(),
|
||||
arcRadius: 10,
|
||||
angle: 2 * math.pi,
|
||||
),
|
||||
isNotNull,
|
||||
);
|
||||
});
|
||||
|
||||
group('copyWith', () {
|
||||
test(
|
||||
'copies correctly '
|
||||
'when no argument specified', () {
|
||||
final arcShape = ArcShape(
|
||||
center: Vector2.zero(),
|
||||
arcRadius: 10,
|
||||
angle: 2 * math.pi,
|
||||
);
|
||||
final arcShapeCopied = arcShape.copyWith();
|
||||
|
||||
for (var index = 0; index < arcShape.vertices.length; index++) {
|
||||
expect(
|
||||
arcShape.vertices[index],
|
||||
equals(arcShapeCopied.vertices[index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
'copies correctly '
|
||||
'when all arguments specified', () {
|
||||
final arcShapeExpected = ArcShape(
|
||||
center: Vector2.all(10),
|
||||
arcRadius: 15,
|
||||
angle: 2 * math.pi,
|
||||
);
|
||||
final arcShapeCopied = ArcShape(
|
||||
center: Vector2.zero(),
|
||||
arcRadius: 10,
|
||||
angle: math.pi,
|
||||
).copyWith(
|
||||
center: Vector2.all(10),
|
||||
arcRadius: 15,
|
||||
angle: 2 * math.pi,
|
||||
);
|
||||
|
||||
for (var index = 0; index < arcShapeCopied.vertices.length; index++) {
|
||||
expect(
|
||||
arcShapeCopied.vertices[index],
|
||||
equals(arcShapeExpected.vertices[index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import 'dart:math' as math;
|
||||
import 'package:flame/extensions.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pinball_components/src/components/components.dart';
|
||||
|
||||
void main() {
|
||||
group('BezierCurveShape', () {
|
||||
final controlPoints = [
|
||||
Vector2(0, 0),
|
||||
Vector2(10, 0),
|
||||
Vector2(0, 10),
|
||||
Vector2(10, 10),
|
||||
];
|
||||
|
||||
test('can be instantiated', () {
|
||||
expect(
|
||||
BezierCurveShape(
|
||||
controlPoints: controlPoints,
|
||||
),
|
||||
isNotNull,
|
||||
);
|
||||
});
|
||||
|
||||
group('rotate', () {
|
||||
test('returns vertices rotated', () {
|
||||
const rotationAngle = 2 * math.pi;
|
||||
final controlPoints = [
|
||||
Vector2(0, 0),
|
||||
Vector2(10, 0),
|
||||
Vector2(0, 10),
|
||||
Vector2(10, 10),
|
||||
];
|
||||
|
||||
final bezierCurveShape = BezierCurveShape(
|
||||
controlPoints: controlPoints,
|
||||
);
|
||||
final bezierCurveShapeRotated = BezierCurveShape(
|
||||
controlPoints: controlPoints,
|
||||
)..rotate(rotationAngle);
|
||||
|
||||
for (var index = 0; index < bezierCurveShape.vertices.length; index++) {
|
||||
expect(
|
||||
bezierCurveShape.vertices[index]..rotate(rotationAngle),
|
||||
equals(bezierCurveShapeRotated.vertices[index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
import 'dart:math' as math;
|
||||
import 'package:flame/extensions.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pinball_components/src/components/components.dart';
|
||||
|
||||
void main() {
|
||||
group('EllipseShape', () {
|
||||
test('can be instantiated', () {
|
||||
expect(
|
||||
EllipseShape(
|
||||
center: Vector2.zero(),
|
||||
majorRadius: 10,
|
||||
minorRadius: 8,
|
||||
),
|
||||
isNotNull,
|
||||
);
|
||||
});
|
||||
|
||||
group('rotate', () {
|
||||
test('returns vertices rotated', () {
|
||||
const rotationAngle = 2 * math.pi;
|
||||
final ellipseShape = EllipseShape(
|
||||
center: Vector2.zero(),
|
||||
majorRadius: 10,
|
||||
minorRadius: 8,
|
||||
);
|
||||
final ellipseShapeRotated = EllipseShape(
|
||||
center: Vector2.zero(),
|
||||
majorRadius: 10,
|
||||
minorRadius: 8,
|
||||
)..rotate(rotationAngle);
|
||||
|
||||
for (var index = 0; index < ellipseShape.vertices.length; index++) {
|
||||
expect(
|
||||
ellipseShape.vertices[index]..rotate(rotationAngle),
|
||||
equals(ellipseShapeRotated.vertices[index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group('copyWith', () {
|
||||
test('returns same shape when no properties are passed', () {
|
||||
final ellipseShape = EllipseShape(
|
||||
center: Vector2.zero(),
|
||||
majorRadius: 10,
|
||||
minorRadius: 8,
|
||||
);
|
||||
final ellipseShapeCopied = ellipseShape.copyWith();
|
||||
|
||||
for (var index = 0; index < ellipseShape.vertices.length; index++) {
|
||||
expect(
|
||||
ellipseShape.vertices[index],
|
||||
equals(ellipseShapeCopied.vertices[index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('returns object with updated properties when are passed', () {
|
||||
final ellipseShapeExpected = EllipseShape(
|
||||
center: Vector2.all(10),
|
||||
majorRadius: 10,
|
||||
minorRadius: 8,
|
||||
);
|
||||
final ellipseShapeCopied = EllipseShape(
|
||||
center: Vector2.zero(),
|
||||
majorRadius: 10,
|
||||
minorRadius: 8,
|
||||
).copyWith(center: Vector2.all(10));
|
||||
|
||||
for (var index = 0;
|
||||
index < ellipseShapeCopied.vertices.length;
|
||||
index++) {
|
||||
expect(
|
||||
ellipseShapeCopied.vertices[index],
|
||||
equals(ellipseShapeExpected.vertices[index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
// ignore_for_file: cascade_invocations
|
||||
|
||||
import 'package:flame/components.dart';
|
||||
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(PinballGameTest.create);
|
||||
|
||||
group('JetpackRamp', () {
|
||||
flameTester.test(
|
||||
'loads correctly',
|
||||
(game) async {
|
||||
final ramp = JetpackRamp(
|
||||
position: Vector2.zero(),
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
expect(game.contains(ramp), isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
group('children', () {
|
||||
flameTester.test(
|
||||
'has only one Pathway.arc',
|
||||
(game) async {
|
||||
final ramp = JetpackRamp(
|
||||
position: Vector2.zero(),
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
expect(
|
||||
() => ramp.children.singleWhere(
|
||||
(component) => component is Pathway,
|
||||
),
|
||||
returnsNormally,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.test(
|
||||
'has a two RampOpenings for the ramp',
|
||||
(game) async {
|
||||
final ramp = JetpackRamp(
|
||||
position: Vector2.zero(),
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
final rampAreas = ramp.children.whereType<RampOpening>();
|
||||
expect(rampAreas.length, 2);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// ignore_for_file: cascade_invocations
|
||||
|
||||
import 'package:flame/components.dart';
|
||||
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(PinballGameTest.create);
|
||||
|
||||
group('LauncherRamp', () {
|
||||
flameTester.test(
|
||||
'loads correctly',
|
||||
(game) async {
|
||||
final ramp = LauncherRamp(
|
||||
position: Vector2.zero(),
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
expect(game.contains(ramp), isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
group('constructor', () {
|
||||
flameTester.test(
|
||||
'positions correctly',
|
||||
(game) async {
|
||||
final position = Vector2.all(10);
|
||||
final ramp = LauncherRamp(
|
||||
position: position,
|
||||
);
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
expect(ramp.position, equals(position));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('children', () {
|
||||
flameTester.test(
|
||||
'has two Pathway',
|
||||
(game) async {
|
||||
final ramp = LauncherRamp(
|
||||
position: Vector2.zero(),
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
final pathways = ramp.children.whereType<Pathway>().toList();
|
||||
expect(pathways.length, 2);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.test(
|
||||
'has a two RampOpenings for the ramp',
|
||||
(game) async {
|
||||
final ramp = LauncherRamp(
|
||||
position: Vector2.zero(),
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(ramp);
|
||||
|
||||
final rampAreas = ramp.children.whereType<RampOpening>().toList();
|
||||
expect(rampAreas.length, 2);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,243 +0,0 @@
|
||||
// ignore_for_file: cascade_invocations, prefer_const_constructors
|
||||
import 'dart:math' as math;
|
||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pinball/game/game.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(Forge2DGame.new);
|
||||
|
||||
group('Pathway', () {
|
||||
const width = 50.0;
|
||||
|
||||
group('straight', () {
|
||||
flameTester.test(
|
||||
'loads correctly',
|
||||
(game) async {
|
||||
final pathway = Pathway.straight(
|
||||
start: Vector2(10, 10),
|
||||
end: Vector2(20, 20),
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(game.contains(pathway), isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
group('color', () {
|
||||
flameTester.test(
|
||||
'has transparent color by default when no color is specified',
|
||||
(game) async {
|
||||
final pathway = Pathway.straight(
|
||||
start: Vector2(10, 10),
|
||||
end: Vector2(20, 20),
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(game.contains(pathway), isTrue);
|
||||
expect(pathway.paint, isNotNull);
|
||||
expect(
|
||||
pathway.paint.color,
|
||||
equals(Color.fromARGB(0, 0, 0, 0)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.test(
|
||||
'has a color when is specified',
|
||||
(game) async {
|
||||
const defaultColor = Colors.blue;
|
||||
|
||||
final pathway = Pathway.straight(
|
||||
color: defaultColor,
|
||||
start: Vector2(10, 10),
|
||||
end: Vector2(20, 20),
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(game.contains(pathway), isTrue);
|
||||
expect(pathway.paint, isNotNull);
|
||||
expect(pathway.paint.color.value, equals(defaultColor.value));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('body', () {
|
||||
flameTester.test(
|
||||
'is static',
|
||||
(game) async {
|
||||
final pathway = Pathway.straight(
|
||||
start: Vector2(10, 10),
|
||||
end: Vector2(20, 20),
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(pathway.body.bodyType, equals(BodyType.static));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('fixtures', () {
|
||||
flameTester.test(
|
||||
'has only one ChainShape when singleWall is true',
|
||||
(game) async {
|
||||
final pathway = Pathway.straight(
|
||||
start: Vector2(10, 10),
|
||||
end: Vector2(20, 20),
|
||||
width: width,
|
||||
singleWall: true,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(pathway.body.fixtures.length, 1);
|
||||
final fixture = pathway.body.fixtures[0];
|
||||
expect(fixture, isA<Fixture>());
|
||||
expect(fixture.shape.shapeType, equals(ShapeType.chain));
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.test(
|
||||
'has two ChainShape when singleWall is false (default)',
|
||||
(game) async {
|
||||
final pathway = Pathway.straight(
|
||||
start: Vector2(10, 10),
|
||||
end: Vector2(20, 20),
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(pathway.body.fixtures.length, 2);
|
||||
for (final fixture in pathway.body.fixtures) {
|
||||
expect(fixture, isA<Fixture>());
|
||||
expect(fixture.shape.shapeType, equals(ShapeType.chain));
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('arc', () {
|
||||
flameTester.test(
|
||||
'loads correctly',
|
||||
(game) async {
|
||||
final pathway = Pathway.arc(
|
||||
center: Vector2.zero(),
|
||||
width: width,
|
||||
radius: 100,
|
||||
angle: math.pi / 2,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(game.contains(pathway), isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
group('body', () {
|
||||
flameTester.test(
|
||||
'is static',
|
||||
(game) async {
|
||||
final pathway = Pathway.arc(
|
||||
center: Vector2.zero(),
|
||||
width: width,
|
||||
radius: 100,
|
||||
angle: math.pi / 2,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(pathway.body.bodyType, equals(BodyType.static));
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('ellipse', () {
|
||||
flameTester.test(
|
||||
'loads correctly',
|
||||
(game) async {
|
||||
final pathway = Pathway.ellipse(
|
||||
center: Vector2.zero(),
|
||||
width: width,
|
||||
majorRadius: 150,
|
||||
minorRadius: 70,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(game.contains(pathway), isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
group('body', () {
|
||||
flameTester.test(
|
||||
'is static',
|
||||
(game) async {
|
||||
final pathway = Pathway.ellipse(
|
||||
center: Vector2.zero(),
|
||||
width: width,
|
||||
majorRadius: 150,
|
||||
minorRadius: 70,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(pathway.body.bodyType, equals(BodyType.static));
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('bezier curve', () {
|
||||
final controlPoints = [
|
||||
Vector2(0, 0),
|
||||
Vector2(50, 0),
|
||||
Vector2(0, 50),
|
||||
Vector2(50, 50),
|
||||
];
|
||||
|
||||
flameTester.test(
|
||||
'loads correctly',
|
||||
(game) async {
|
||||
final pathway = Pathway.bezierCurve(
|
||||
controlPoints: controlPoints,
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(game.contains(pathway), isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
group('body', () {
|
||||
flameTester.test(
|
||||
'is static',
|
||||
(game) async {
|
||||
final pathway = Pathway.bezierCurve(
|
||||
controlPoints: controlPoints,
|
||||
width: width,
|
||||
);
|
||||
await game.ready();
|
||||
await game.ensureAdd(pathway);
|
||||
|
||||
expect(pathway.body.bodyType, equals(BodyType.static));
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in new issue