refactor: sparky+launcher into one path

pull/40/head
RuiAlonso 4 years ago
parent 3a6435cb29
commit 30f3f93aca

@ -5,11 +5,11 @@ export 'bonus_word.dart';
export 'flipper.dart';
export 'jetpack_ramp.dart';
export 'joint_anchor.dart';
export 'launcher_ramp.dart';
export 'layer.dart';
export 'pathway.dart';
export 'plunger.dart';
export 'round_bumper.dart';
export 'score_points.dart';
export 'sling_shot.dart';
export 'sparky_ramp.dart';
export 'wall.dart';

@ -0,0 +1,122 @@
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/game.dart';
/// {@template launcher_ramp}
/// Represent the launcher green and upper right yellow ramps for the game.
///
/// Group of [Component]s composed by a [Pathway.arc] as the upper curve ramp,
/// a [Pathway.straight] for the launcher straight ramp, and two
/// [LauncherRampOpening] at the entrance and exit of the ramp, to detect when
/// a ball gets into/out of the ramp.
/// {@endtemplate}
class LauncherRamp extends Component with HasGameRef<PinballGame> {
/// {@macro launcher_ramp}
LauncherRamp({
required this.position,
});
final double _radius = 300;
final double _width = 80;
final double _angle = radians(200);
/// The position of this [LauncherRamp]
final Vector2 position;
@override
Future<void> onLoad() async {
await add(
Pathway.straight(
color: const Color.fromARGB(255, 34, 255, 0),
position: position,
start: Vector2(0, 0),
end: Vector2(0, 600),
width: 80,
),
);
await add(
Pathway.arc(
color: const Color.fromARGB(255, 251, 255, 0),
position: position + Vector2(-28.8, -6),
radius: _radius,
angle: _angle,
width: _width,
layer: Layer.launcher,
),
);
await add(
LauncherRampOpening(
position: position + Vector2(-46.5, -9),
orientation: RampOrientation.down,
rotation: radians(13),
),
);
await add(
LauncherRampOpening(
position: position + Vector2(4, 0),
orientation: RampOrientation.down,
),
);
gameRef.addContactCallback(LauncherRampOpeningBallContactCallback());
}
}
/// {@template launcher_ramp_opening}
/// [RampOpening] with [Layer.launcher] to filter [Ball]s collisions
/// inside [LauncherRamp].
/// {@endtemplate}
class LauncherRampOpening extends RampOpening {
/// {@macro launcher_ramp_opening}
LauncherRampOpening({
required Vector2 position,
double rotation = 0,
required RampOrientation orientation,
}) : _rotation = rotation,
_orientation = orientation,
super(
position: position,
layer: Layer.launcher,
);
/// Orientation of entrance/exit of [LauncherRamp] where
/// this [LauncherRampOpening] is placed.
final RampOrientation _orientation;
/// Rotation of the [RampOpening] to place it right at the
/// entrance/exit of [LauncherRamp].
final double _rotation;
/// Size of the [RampOpening] placed at the entrance/exit of [LauncherRamp].
final int _size = 7;
@override
RampOrientation get orientation => _orientation;
@override
Shape get shape => PolygonShape()
..set([
Vector2(-_size / 2, -.1)..rotate(_rotation),
Vector2(-_size / 2, .1)..rotate(_rotation),
Vector2(_size / 2, .1)..rotate(_rotation),
Vector2(_size / 2, -.1)..rotate(_rotation),
]);
}
/// {@template launcher_ramp_opening_ball_contact_callback}
/// Detects when a [Ball] enters or exits the [LauncherRamp] through a
/// [LauncherRampOpening].
/// {@endtemplate}
class LauncherRampOpeningBallContactCallback
extends RampOpeningBallContactCallback<LauncherRampOpening> {
/// {@macro launcher_ramp_opening_ball_contact_callback}
LauncherRampOpeningBallContactCallback() : super();
/// Collection of balls inside [LauncherRamp].
final _ballsInsideLauncher = <Ball>{};
@override
Set get ballsInside => _ballsInsideLauncher;
}

@ -32,8 +32,8 @@ enum Layer {
/// Collide only with Jetpack group elements.
jetpack,
/// Collide only with Sparky group elements.
sparky,
/// Collide only with Launcher group elements.
launcher,
}
/// Utility methods for [Layer].
@ -45,7 +45,7 @@ extension LayerX on Layer {
return 0xFFFF;
case Layer.jetpack:
return 0x0010;
case Layer.sparky:
case Layer.launcher:
return 0x0100;
}
}

@ -1,111 +0,0 @@
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/game.dart';
/// {@template sparky_ramp}
/// Represent the upper right yellow ramp for the game.
///
/// Group of [Component]s composed by a [Pathway.arc] as the ramp, and two
/// [SparkyRampOpening] at the entrance and exit of the ramp, to detect when
/// a ball gets into/out of the ramp.
/// {@endtemplate}
class SparkyRamp extends Component with HasGameRef<PinballGame> {
/// {@macro sparky_ramp}
SparkyRamp({
required this.position,
});
final double _radius = 300;
final double _width = 80;
final double _angle = radians(200);
/// The position of this [SparkyRamp]
final Vector2 position;
@override
Future<void> onLoad() async {
await add(
Pathway.arc(
color: const Color.fromARGB(255, 251, 255, 0),
position: position,
radius: _radius,
angle: _angle,
width: _width,
layer: Layer.sparky,
),
);
await add(
SparkyRampOpening(
position: position + Vector2(-18, -2),
orientation: RampOrientation.down,
rotation: radians(13),
),
);
await add(
SparkyRampOpening(
position: position + Vector2(33, 6),
orientation: RampOrientation.down,
),
);
gameRef.addContactCallback(SparkyRampOpeningBallContactCallback());
}
}
/// {@template sparky_ramp_opening}
/// [RampOpening] with [Layer.sparky] to filter [Ball]s collisions
/// inside [SparkyRamp].
/// {@endtemplate}
class SparkyRampOpening extends RampOpening {
/// {@macro sparky_ramp_opening}
SparkyRampOpening({
required Vector2 position,
double rotation = 0,
required RampOrientation orientation,
}) : _rotation = rotation,
_orientation = orientation,
super(
position: position,
layer: Layer.sparky,
);
/// Orientation of entrance/exit of [SparkyRamp] where
/// this [SparkyRampOpening] is placed.
final RampOrientation _orientation;
/// Rotation of the [RampOpening] to place it right at the
/// entrance/exit of [SparkyRamp].
final double _rotation;
/// Size of the [RampOpening] placed at the entrance/exit of [SparkyRamp].
final int _size = 7;
@override
RampOrientation get orientation => _orientation;
@override
Shape get shape => PolygonShape()
..set([
Vector2(-_size / 2, -.1)..rotate(_rotation),
Vector2(-_size / 2, .1)..rotate(_rotation),
Vector2(_size / 2, .1)..rotate(_rotation),
Vector2(_size / 2, -.1)..rotate(_rotation),
]);
}
/// {@template sparky_ramp_opening_ball_contact_callback}
/// Detects when a [Ball] enters or exits the [SparkyRamp] through a
/// [SparkyRampOpening].
/// {@endtemplate}
class SparkyRampOpeningBallContactCallback
extends RampOpeningBallContactCallback<SparkyRampOpening> {
/// {@macro sparky_ramp_opening_ball_contact_callback}
SparkyRampOpeningBallContactCallback() : super();
/// Collection of balls inside [SparkyRamp].
final _ballsInsideSparky = <Ball>{};
@override
Set get ballsInside => _ballsInsideSparky;
}

@ -1,7 +1,6 @@
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:ui';
import 'package:flame/input.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
@ -31,14 +30,6 @@ class PinballGame extends Forge2DGame
Vector2(-150, -150),
);
late final sparkyRampPosition = screenToWorld(
Vector2(
camera.viewport.effectiveSize.x / 2,
camera.viewport.effectiveSize.y / 2,
) +
Vector2(80, -100),
);
@override
void onAttach() {
super.onAttach();
@ -126,16 +117,6 @@ class PinballGame extends Forge2DGame
}
Future<void> _addPaths() async {
await add(
Pathway.straight(
color: const Color.fromARGB(255, 34, 255, 0),
position: launcherRampPosition,
start: Vector2(0, 0),
end: Vector2(0, 600),
width: 80,
),
);
await add(
JetpackRamp(
position: jetpackRampPosition,
@ -143,8 +124,8 @@ class PinballGame extends Forge2DGame
);
await add(
SparkyRamp(
position: sparkyRampPosition,
LauncherRamp(
position: launcherRampPosition,
),
);
}

@ -50,8 +50,8 @@ void main() {
group('LayerX', () {
test('all types are different', () {
expect(Layer.all.maskBits, isNot(equals(Layer.jetpack.maskBits)));
expect(Layer.jetpack.maskBits, isNot(equals(Layer.sparky.maskBits)));
expect(Layer.sparky.maskBits, isNot(equals(Layer.all.maskBits)));
expect(Layer.jetpack.maskBits, isNot(equals(Layer.launcher.maskBits)));
expect(Layer.launcher.maskBits, isNot(equals(Layer.all.maskBits)));
});
test('all type has default maskBits', () {
@ -62,8 +62,8 @@ void main() {
expect(Layer.jetpack.maskBits, equals(0x0010));
});
test('sparky type has 0x0100 maskBits', () {
expect(Layer.sparky.maskBits, equals(0x0100));
test('launcher type has 0x0100 maskBits', () {
expect(Layer.launcher.maskBits, equals(0x0100));
});
});

@ -9,17 +9,17 @@ import 'package:pinball/game/game.dart';
import '../../helpers/helpers.dart';
class MockSparkyRampArea extends Mock implements SparkyRampOpening {}
class MockLauncherRampArea extends Mock implements LauncherRampOpening {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(PinballGameTest.create);
group('SparkyRamp', () {
group('LauncherRamp', () {
flameTester.test(
'loads correctly',
(game) async {
final ramp = SparkyRamp(
final ramp = LauncherRamp(
position: Vector2.zero(),
);
await game.ready();
@ -34,7 +34,7 @@ void main() {
'positions correctly',
(game) async {
final position = Vector2.all(10);
final ramp = SparkyRamp(
final ramp = LauncherRamp(
position: position,
);
await game.ensureAdd(ramp);
@ -46,46 +46,42 @@ void main() {
group('children', () {
flameTester.test(
'has only one Pathway.arc',
'has two Pathway',
(game) async {
final ramp = SparkyRamp(
final ramp = LauncherRamp(
position: Vector2.zero(),
);
await game.ready();
await game.ensureAdd(ramp);
expect(
() => ramp.children.singleWhere(
(component) => component is Pathway,
),
returnsNormally,
);
final pathways = ramp.children.whereType<Pathway>().toList();
expect(pathways.length, 2);
},
);
flameTester.test(
'has a two sensors for the ramp',
(game) async {
final ramp = SparkyRamp(
final ramp = LauncherRamp(
position: Vector2.zero(),
);
await game.ready();
await game.ensureAdd(ramp);
final rampAreas =
ramp.children.whereType<SparkyRampOpening>().toList();
ramp.children.whereType<LauncherRampOpening>().toList();
expect(rampAreas.length, 2);
},
);
});
});
group('SparkyRampOpening', () {
group('LauncherRampOpening', () {
flameTester.test(
'orientation is down',
(game) async {
final position = Vector2.all(10);
final ramp = SparkyRampOpening(
final ramp = LauncherRampOpening(
position: position,
orientation: RampOrientation.down,
);
@ -97,10 +93,10 @@ void main() {
);
});
group('SparkyRampOpeningBallContactCallback', () {
group('LauncherRampOpeningBallContactCallback', () {
test('has no ball inside on creation', () {
expect(
SparkyRampOpeningBallContactCallback().ballsInside,
LauncherRampOpeningBallContactCallback().ballsInside,
equals(<Ball>{}),
);
});

@ -88,11 +88,11 @@ void main() {
);
flameTester.test(
'has only one SparkyRamp',
'has only one LauncherRamp',
(game) async {
await game.ready();
final rampAreas = game.children.whereType<SparkyRamp>().toList();
final rampAreas = game.children.whereType<LauncherRamp>().toList();
expect(rampAreas.length, 1);
},
);

Loading…
Cancel
Save