mirror of https://github.com/flutter/pinball.git
parent
965c14be60
commit
0c240f12de
@ -0,0 +1,98 @@
|
|||||||
|
// ignore_for_file: avoid_renaming_method_parameters
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
|
||||||
|
/// Indicates the orientation of a ramp entrance/exit.
|
||||||
|
///
|
||||||
|
/// Used to know if a ramp is facing up or down on the board.
|
||||||
|
enum RampOrientation {
|
||||||
|
/// Facing up on the board.
|
||||||
|
up,
|
||||||
|
|
||||||
|
/// Facing down on the board.
|
||||||
|
down,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template ramp_opening}
|
||||||
|
/// [BodyComponent] located at the entrance and exit of a ramp.
|
||||||
|
///
|
||||||
|
/// [RampOpeningBallContactCallback] detects when a [Ball] passes
|
||||||
|
/// through this opening. By default openings are [Layer.board] that
|
||||||
|
/// means opening are at ground level, not over board.
|
||||||
|
/// {@endtemplate}
|
||||||
|
abstract class RampOpening extends BodyComponent with InitialPosition {
|
||||||
|
/// {@macro ramp_opening}
|
||||||
|
RampOpening({
|
||||||
|
required Layer pathwayLayer,
|
||||||
|
Layer? openingLayer,
|
||||||
|
}) : _pathwayLayer = pathwayLayer,
|
||||||
|
_openingLayer = openingLayer ?? Layer.board;
|
||||||
|
|
||||||
|
final Layer _openingLayer;
|
||||||
|
final Layer _pathwayLayer;
|
||||||
|
|
||||||
|
/// Mask of category bits for collision with [RampOpening].
|
||||||
|
Layer get openingLayer => _openingLayer;
|
||||||
|
|
||||||
|
/// Mask of category bits for collision inside [Pathway].
|
||||||
|
Layer get pathwayLayer => _pathwayLayer;
|
||||||
|
|
||||||
|
/// The [Shape] of the [RampOpening].
|
||||||
|
Shape get shape;
|
||||||
|
|
||||||
|
/// Orientation of the [RampOpening] entrance/exit
|
||||||
|
// TODO(ruimiguel): Try to remove the need of [RampOrientation] for collision
|
||||||
|
// calculations.
|
||||||
|
RampOrientation get orientation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Body createBody() {
|
||||||
|
final fixtureDef = FixtureDef(shape)
|
||||||
|
..isSensor = true
|
||||||
|
..filter.categoryBits = _openingLayer.maskBits;
|
||||||
|
|
||||||
|
final bodyDef = BodyDef()
|
||||||
|
..userData = this
|
||||||
|
..position = initialPosition
|
||||||
|
..type = BodyType.static;
|
||||||
|
|
||||||
|
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template ramp_opening_ball_contact_callback}
|
||||||
|
/// Detects when a [Ball] enters or exits a [Pathway] ramp through a
|
||||||
|
/// [RampOpening].
|
||||||
|
///
|
||||||
|
/// Modifies [Ball]'s maskBits while it is inside the ramp. When [Ball] exits,
|
||||||
|
/// sets maskBits to collide with all elements.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class RampOpeningBallContactCallback<Opening extends RampOpening>
|
||||||
|
extends ContactCallback<Ball, Opening> {
|
||||||
|
/// Collection of balls inside ramp pathway.
|
||||||
|
final _ballsInside = <Ball>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void begin(Ball ball, Opening opening, Contact _) {
|
||||||
|
late final Layer layer;
|
||||||
|
if (!_ballsInside.contains(ball)) {
|
||||||
|
layer = opening.pathwayLayer;
|
||||||
|
_ballsInside.add(ball);
|
||||||
|
} else {
|
||||||
|
layer = Layer.board;
|
||||||
|
_ballsInside.remove(ball);
|
||||||
|
}
|
||||||
|
|
||||||
|
ball.layer = layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void end(Ball ball, Opening opening, Contact _) {
|
||||||
|
final isBallOutsideOpening = opening.orientation == RampOrientation.up
|
||||||
|
? ball.body.position.y > opening.body.position.y
|
||||||
|
: ball.body.position.y < opening.body.position.y;
|
||||||
|
|
||||||
|
if (isBallOutsideOpening) ball.layer = Layer.board;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue