mirror of https://github.com/flutter/pinball.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
3.4 KiB
111 lines
3.4 KiB
// ignore_for_file: avoid_renaming_method_parameters
|
|
|
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
import 'package:pinball_components/pinball_components.dart';
|
|
|
|
/// {@template layer_entrance_orientation}
|
|
/// Determines if a layer entrance is oriented [up] or [down] on the board.
|
|
/// {@endtemplate}
|
|
enum LayerEntranceOrientation {
|
|
/// Facing up on the Board.
|
|
up,
|
|
|
|
/// Facing down on the Board.
|
|
down,
|
|
}
|
|
|
|
/// {@template layer_sensor}
|
|
/// [BodyComponent] located at the entrance and exit of a [Layer].
|
|
///
|
|
/// [LayerSensorBallContactCallback] detects when a [Ball] passes
|
|
/// through this sensor.
|
|
///
|
|
/// By default the base [layer] is set to [Layer.board] and the
|
|
/// [outsidePriority] is set to the lowest possible [Layer].
|
|
/// {@endtemplate}
|
|
abstract class LayerSensor extends BodyComponent with InitialPosition, Layered {
|
|
/// {@macro layer_sensor}
|
|
LayerSensor({
|
|
required Layer insideLayer,
|
|
Layer? outsideLayer,
|
|
required int insidePriority,
|
|
int? outsidePriority,
|
|
required this.orientation,
|
|
}) : _insideLayer = insideLayer,
|
|
_outsideLayer = outsideLayer ?? Layer.board,
|
|
_insidePriority = insidePriority,
|
|
_outsidePriority = outsidePriority ?? RenderPriority.ballOnBoard {
|
|
layer = Layer.opening;
|
|
}
|
|
final Layer _insideLayer;
|
|
final Layer _outsideLayer;
|
|
final int _insidePriority;
|
|
final int _outsidePriority;
|
|
|
|
/// Mask bits value for collisions on [Layer].
|
|
Layer get insideLayer => _insideLayer;
|
|
|
|
/// Mask bits value for collisions outside of [Layer].
|
|
Layer get outsideLayer => _outsideLayer;
|
|
|
|
/// Render priority for the [Ball] on [Layer].
|
|
int get insidePriority => _insidePriority;
|
|
|
|
/// Render priority for the [Ball] outside of [Layer].
|
|
int get outsidePriority => _outsidePriority;
|
|
|
|
/// The [Shape] of the [LayerSensor].
|
|
Shape get shape;
|
|
|
|
/// {@macro layer_entrance_orientation}
|
|
// TODO(ruimiguel): Try to remove the need of [LayerEntranceOrientation] for
|
|
// collision calculations.
|
|
final LayerEntranceOrientation orientation;
|
|
|
|
@override
|
|
Body createBody() {
|
|
final fixtureDef = FixtureDef(
|
|
shape,
|
|
isSensor: true,
|
|
);
|
|
final bodyDef = BodyDef(
|
|
position: initialPosition,
|
|
userData: this,
|
|
);
|
|
|
|
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
|
}
|
|
}
|
|
|
|
/// {@template layer_sensor_ball_contact_callback}
|
|
/// Detects when a [Ball] enters or exits a [Layer] through a [LayerSensor].
|
|
///
|
|
/// Modifies [Ball]'s [Layer] and render priority depending on whether the
|
|
/// [Ball] is on or outside of a [Layer].
|
|
/// {@endtemplate}
|
|
class LayerSensorBallContactCallback<LayerEntrance extends LayerSensor>
|
|
extends ContactCallback<Ball, LayerEntrance> {
|
|
@override
|
|
void begin(Ball ball, LayerEntrance layerEntrance, Contact _) {
|
|
if (ball.layer != layerEntrance.insideLayer) {
|
|
final isBallEnteringOpening =
|
|
(layerEntrance.orientation == LayerEntranceOrientation.down &&
|
|
ball.body.linearVelocity.y < 0) ||
|
|
(layerEntrance.orientation == LayerEntranceOrientation.up &&
|
|
ball.body.linearVelocity.y > 0);
|
|
|
|
if (isBallEnteringOpening) {
|
|
ball
|
|
..layer = layerEntrance.insideLayer
|
|
..priority = layerEntrance.insidePriority
|
|
..reorderChildren();
|
|
}
|
|
} else {
|
|
ball
|
|
..layer = layerEntrance.outsideLayer
|
|
..priority = layerEntrance.outsidePriority
|
|
..reorderChildren();
|
|
}
|
|
}
|
|
}
|