feat: allow jetpack ramp to be over the board

pull/40/head
RuiAlonso 4 years ago
parent 7c76b70bba
commit 688941b9fd

@ -12,7 +12,7 @@ class Ball extends BodyComponent<PinballGame> with Layered {
required Vector2 position, required Vector2 position,
Layer? layer, Layer? layer,
}) : _position = position, }) : _position = position,
_layer = layer ?? Layer.all; _layer = layer ?? Layer.board;
/// The initial position of the [Ball] body. /// The initial position of the [Ball] body.
final Vector2 _position; final Vector2 _position;

@ -19,8 +19,6 @@ class JetpackRamp extends Component with HasGameRef<PinballGame> {
final double _width = 80; final double _width = 80;
final double _angle = radians(210); final double _angle = radians(210);
final double _rotation = radians(-10); final double _rotation = radians(-10);
final double _entranceRotation = radians(15);
final double _exitRotation = radians(-5);
/// The position of this [JetpackRamp] /// The position of this [JetpackRamp]
final Vector2 position; final Vector2 position;
@ -41,16 +39,16 @@ class JetpackRamp extends Component with HasGameRef<PinballGame> {
await add( await add(
JetpackRampOpening( JetpackRampOpening(
position: position + Vector2(-10.5, 0), position: position + Vector2(-11, .5),
rotation: _entranceRotation,
orientation: RampOrientation.down, orientation: RampOrientation.down,
rotation: radians(15),
), ),
); );
await add( await add(
JetpackRampOpening( JetpackRampOpening(
position: position + Vector2(20.5, 3), position: position + Vector2(20.5, 3.4),
rotation: _exitRotation,
orientation: RampOrientation.down, orientation: RampOrientation.down,
rotation: radians(-9),
), ),
); );
@ -66,13 +64,15 @@ class JetpackRampOpening extends RampOpening {
/// {@macro jetpack_ramp_opening} /// {@macro jetpack_ramp_opening}
JetpackRampOpening({ JetpackRampOpening({
required Vector2 position, required Vector2 position,
double rotation = 0,
required RampOrientation orientation, required RampOrientation orientation,
double rotation = 0,
Layer? openingLayer,
}) : _rotation = rotation, }) : _rotation = rotation,
_orientation = orientation, _orientation = orientation,
super( super(
position: position, position: position,
layer: Layer.jetpack, pathwayLayer: Layer.jetpack,
openingLayer: openingLayer,
); );
/// Orientation of entrance/exit of [JetpackRamp] where /// Orientation of entrance/exit of [JetpackRamp] where

@ -33,6 +33,7 @@ class LauncherRamp extends Component with HasGameRef<PinballGame> {
start: Vector2(0, 0), start: Vector2(0, 0),
end: Vector2(0, 600), end: Vector2(0, 600),
width: 80, width: 80,
layer: Layer.launcher,
), ),
); );
@ -48,7 +49,7 @@ class LauncherRamp extends Component with HasGameRef<PinballGame> {
); );
await add( await add(
LauncherRampOpening( LauncherRampOpening(
position: position + Vector2(-46.5, -9), position: position + Vector2(-46.5, -8.5),
orientation: RampOrientation.down, orientation: RampOrientation.down,
rotation: radians(13), rotation: radians(13),
), ),
@ -78,7 +79,7 @@ class LauncherRampOpening extends RampOpening {
_orientation = orientation, _orientation = orientation,
super( super(
position: position, position: position,
layer: Layer.launcher, pathwayLayer: Layer.launcher,
); );
/// Orientation of entrance/exit of [LauncherRamp] where /// Orientation of entrance/exit of [LauncherRamp] where

@ -29,6 +29,9 @@ enum Layer {
/// Collide with all elements. /// Collide with all elements.
all, all,
/// Collide only with board elements (the ground level).
board,
/// Collide only with Jetpack group elements. /// Collide only with Jetpack group elements.
jetpack, jetpack,
@ -43,6 +46,8 @@ extension LayerX on Layer {
switch (this) { switch (this) {
case Layer.all: case Layer.all:
return 0xFFFF; return 0xFFFF;
case Layer.board:
return 0xFF0F;
case Layer.jetpack: case Layer.jetpack:
return 0x0010; return 0x0010;
case Layer.launcher: case Layer.launcher:
@ -66,24 +71,31 @@ enum RampOrientation {
/// [BodyComponent] located at the entrance and exit of a ramp. /// [BodyComponent] located at the entrance and exit of a ramp.
/// ///
/// [RampOpeningBallContactCallback] detects when a [Ball] passes /// [RampOpeningBallContactCallback] detects when a [Ball] passes
/// through this opening. /// through this opening. By default openings are [Layer.board] that
/// means opening are at ground level, not over board.
/// {@endtemplate} /// {@endtemplate}
abstract class RampOpening extends BodyComponent { abstract class RampOpening extends BodyComponent {
/// {@macro ramp_opening} /// {@macro ramp_opening}
RampOpening({ RampOpening({
required Vector2 position, required Vector2 position,
required Layer layer, required Layer pathwayLayer,
Layer? openingLayer,
}) : _position = position, }) : _position = position,
_layer = layer { _pathwayLayer = pathwayLayer,
_openingLayer = openingLayer ?? Layer.board {
// TODO(ruialonso): remove paint color for BodyComponent. // TODO(ruialonso): remove paint color for BodyComponent.
// Left white for dev and testing. // Left white for dev and testing.
} }
final Vector2 _position; final Vector2 _position;
final Layer _layer; final Layer _openingLayer;
final Layer _pathwayLayer;
/// Mask of category bits for collision with [RampOpening] /// Mask of category bits for collision with [RampOpening]
Layer get layer => _layer; Layer get openingLayer => _openingLayer;
/// Mask of category bits for collision inside [Pathway]
Layer get pathwayLayer => _pathwayLayer;
/// The [Shape] of the [RampOpening] /// The [Shape] of the [RampOpening]
Shape get shape; Shape get shape;
@ -95,7 +107,7 @@ abstract class RampOpening extends BodyComponent {
Body createBody() { Body createBody() {
final fixtureDef = FixtureDef(shape) final fixtureDef = FixtureDef(shape)
..isSensor = true ..isSensor = true
..filter.categoryBits = _layer.maskBits; ..filter.categoryBits = _openingLayer.maskBits;
final bodyDef = BodyDef() final bodyDef = BodyDef()
..userData = this ..userData = this
@ -126,10 +138,12 @@ abstract class RampOpeningBallContactCallback<Opening extends RampOpening>
) { ) {
Layer layer; Layer layer;
if (!ballsInside.contains(ball)) { if (!ballsInside.contains(ball)) {
layer = opening.layer; layer = opening.pathwayLayer;
print('TOUCH begin (add) layer=$layer');
ballsInside.add(ball); ballsInside.add(ball);
} else { } else {
layer = Layer.all; layer = Layer.board;
print('TOUCH begin (remove) layer=$layer');
ballsInside.remove(ball); ballsInside.remove(ball);
} }
@ -142,13 +156,19 @@ abstract class RampOpeningBallContactCallback<Opening extends RampOpening>
switch (opening.orientation) { switch (opening.orientation) {
case RampOrientation.up: case RampOrientation.up:
print('TOUCH end up');
if (ball.body.position.y > opening._position.y) { if (ball.body.position.y > opening._position.y) {
layer = Layer.all; print('layer=$layer');
layer = Layer.board;
print('layer=$layer');
} }
break; break;
case RampOrientation.down: case RampOrientation.down:
print('TOUCH end down');
if (ball.body.position.y < opening._position.y) { if (ball.body.position.y < opening._position.y) {
layer = Layer.all; print('layer=$layer');
layer = Layer.board;
print('layer=$layer');
} }
break; break;
} }

@ -13,7 +13,7 @@ class TestRampOpening extends RampOpening {
required RampOrientation orientation, required RampOrientation orientation,
required Layer layer, required Layer layer,
}) : _orientation = orientation, }) : _orientation = orientation,
super(position: position, layer: layer); super(position: position, pathwayLayer: layer);
final RampOrientation _orientation; final RampOrientation _orientation;
@ -42,20 +42,24 @@ class TestRampOpeningBallContactCallback
void main() { void main() {
group('Layer', () { group('Layer', () {
test('has three values', () { test('has four values', () {
expect(Layer.values.length, equals(3)); expect(Layer.values.length, equals(4));
}); });
}); });
group('LayerX', () { group('LayerX', () {
test('all types are different', () { test('all types are different', () {
expect(Layer.all.maskBits, isNot(equals(Layer.jetpack.maskBits))); expect(Layer.all.maskBits, isNot(equals(Layer.board.maskBits)));
expect(Layer.board.maskBits, isNot(equals(Layer.jetpack.maskBits)));
expect(Layer.jetpack.maskBits, isNot(equals(Layer.launcher.maskBits))); expect(Layer.jetpack.maskBits, isNot(equals(Layer.launcher.maskBits)));
expect(Layer.launcher.maskBits, isNot(equals(Layer.all.maskBits))); expect(Layer.launcher.maskBits, isNot(equals(Layer.board.maskBits)));
}); });
test('all type has default maskBits', () { test('all type has 0xFFFF maskBits', () {
expect(Layer.all.maskBits, equals(0xFFFF)); expect(Layer.all.maskBits, equals(0xFF0F));
});
test('board type has 0xFF0F maskBits', () {
expect(Layer.board.maskBits, equals(0xFF0F));
}); });
test('jetpack type has 0x010 maskBits', () { test('jetpack type has 0x010 maskBits', () {
@ -77,7 +81,7 @@ void main() {
final ramp = TestRampOpening( final ramp = TestRampOpening(
position: Vector2.zero(), position: Vector2.zero(),
orientation: RampOrientation.down, orientation: RampOrientation.down,
layer: Layer.all, layer: Layer.board,
); );
await game.ready(); await game.ready();
await game.ensureAdd(ramp); await game.ensureAdd(ramp);
@ -94,7 +98,7 @@ void main() {
final ramp = TestRampOpening( final ramp = TestRampOpening(
position: position, position: position,
orientation: RampOrientation.down, orientation: RampOrientation.down,
layer: Layer.all, layer: Layer.board,
); );
await game.ensureAdd(ramp); await game.ensureAdd(ramp);
@ -109,7 +113,7 @@ void main() {
final ramp = TestRampOpening( final ramp = TestRampOpening(
position: Vector2.zero(), position: Vector2.zero(),
orientation: RampOrientation.down, orientation: RampOrientation.down,
layer: Layer.all, layer: Layer.board,
); );
await game.ensureAdd(ramp); await game.ensureAdd(ramp);
@ -213,7 +217,7 @@ void main() {
callback.end(ball, area, MockContact()); callback.end(ball, area, MockContact());
verifyNever(() => ball.layer = Layer.all); verifyNever(() => ball.layer = Layer.board);
}); });
test( test(
@ -240,7 +244,7 @@ void main() {
callback.end(ball, area, MockContact()); callback.end(ball, area, MockContact());
verifyNever(() => ball.layer = Layer.all); verifyNever(() => ball.layer = Layer.board);
}); });
test( test(
@ -267,7 +271,7 @@ void main() {
callback.end(ball, area, MockContact()); callback.end(ball, area, MockContact());
verify(() => ball.layer = Layer.all); verify(() => ball.layer = Layer.board);
}); });
test( test(
@ -289,11 +293,11 @@ void main() {
callback.begin(ball, area, MockContact()); callback.begin(ball, area, MockContact());
expect(callback._ballsInside.isEmpty, isTrue); expect(callback._ballsInside.isEmpty, isTrue);
verify(() => ball.layer = Layer.all).called(1); verify(() => ball.layer = Layer.board).called(1);
callback.end(ball, area, MockContact()); callback.end(ball, area, MockContact());
verify(() => ball.layer = Layer.all).called(1); verify(() => ball.layer = Layer.board).called(1);
}); });
test( test(
@ -315,11 +319,11 @@ void main() {
callback.begin(ball, area, MockContact()); callback.begin(ball, area, MockContact());
expect(callback._ballsInside.isEmpty, isTrue); expect(callback._ballsInside.isEmpty, isTrue);
verify(() => ball.layer = Layer.all).called(1); verify(() => ball.layer = Layer.board).called(1);
callback.end(ball, area, MockContact()); callback.end(ball, area, MockContact());
verify(() => ball.layer = Layer.all).called(1); verify(() => ball.layer = Layer.board).called(1);
}); });
}); });
} }

Loading…
Cancel
Save