fix: improved entering SpaceshipRamp consitency (#385)

pull/388/head
Alejandro Santiago 3 years ago committed by GitHub
parent 54b0bc6e17
commit eb8cc4bb6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -42,7 +42,7 @@ class SpaceshipRamp extends Component {
_SpaceshipRampBackground(), _SpaceshipRampBackground(),
_SpaceshipRampBoardOpening()..initialPosition = Vector2(3.4, -39.5), _SpaceshipRampBoardOpening()..initialPosition = Vector2(3.4, -39.5),
_SpaceshipRampForegroundRailing(), _SpaceshipRampForegroundRailing(),
_SpaceshipRampBase()..initialPosition = Vector2(3.4, -42.5), SpaceshipRampBase()..initialPosition = Vector2(3.4, -42.5),
_SpaceshipRampBackgroundRailingSpriteComponent(), _SpaceshipRampBackgroundRailingSpriteComponent(),
SpaceshipRampArrowSpriteComponent( SpaceshipRampArrowSpriteComponent(
current: bloc.state.hits, current: bloc.state.hits,
@ -255,9 +255,14 @@ class _SpaceshipRampBoardOpening extends BodyComponent
_SpaceshipRampBoardOpeningSpriteComponent(), _SpaceshipRampBoardOpeningSpriteComponent(),
LayerContactBehavior(layer: Layer.spaceshipEntranceRamp) LayerContactBehavior(layer: Layer.spaceshipEntranceRamp)
..applyTo(['inside']), ..applyTo(['inside']),
LayerContactBehavior(layer: Layer.board)..applyTo(['outside']), LayerContactBehavior(
ZIndexContactBehavior(zIndex: ZIndexes.ballOnBoard) layer: Layer.board,
..applyTo(['outside']), onBegin: false,
)..applyTo(['outside']),
ZIndexContactBehavior(
zIndex: ZIndexes.ballOnBoard,
onBegin: false,
)..applyTo(['outside']),
ZIndexContactBehavior(zIndex: ZIndexes.ballOnSpaceshipRamp) ZIndexContactBehavior(zIndex: ZIndexes.ballOnSpaceshipRamp)
..applyTo(['middle', 'inside']), ..applyTo(['middle', 'inside']),
], ],
@ -426,9 +431,19 @@ class _SpaceshipRampForegroundRailingSpriteComponent extends SpriteComponent
} }
} }
class _SpaceshipRampBase extends BodyComponent with Layered, InitialPosition { @visibleForTesting
_SpaceshipRampBase() : super(renderBody: false) { class SpaceshipRampBase extends BodyComponent
layer = Layer.board; with InitialPosition, ContactCallbacks {
SpaceshipRampBase() : super(renderBody: false);
@override
void preSolve(Object other, Contact contact, Manifold oldManifold) {
super.preSolve(other, contact, oldManifold);
if (other is! Layered) return;
// Although, the Layer should already be taking care of the contact
// filtering, this is to ensure the ball doesn't collide with the ramp base
// when the filtering is calculated on different time steps.
contact.setEnabled(other.layer == Layer.board);
} }
@override @override
@ -441,7 +456,7 @@ class _SpaceshipRampBase extends BodyComponent with Layered, InitialPosition {
Vector2(4.1, 1.5), Vector2(4.1, 1.5),
], ],
); );
final bodyDef = BodyDef(position: initialPosition); final bodyDef = BodyDef(position: initialPosition, userData: this);
return world.createBody(bodyDef)..createFixtureFromShape(shape); return world.createBody(bodyDef)..createFixtureFromShape(shape);
} }
} }

@ -2,6 +2,7 @@
import 'package:bloc_test/bloc_test.dart'; import 'package:bloc_test/bloc_test.dart';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
@ -12,6 +13,12 @@ import '../../../helpers/helpers.dart';
class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {} class _MockSpaceshipRampCubit extends Mock implements SpaceshipRampCubit {}
class _MockBall extends Mock implements Ball {}
class _MockContact extends Mock implements Contact {}
class _MockManifold extends Mock implements Manifold {}
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
final assets = [ final assets = [
@ -275,4 +282,46 @@ void main() {
}); });
}); });
}); });
group('SpaceshipRampBase', () {
test('can be instantiated', () {
expect(SpaceshipRampBase(), isA<SpaceshipRampBase>());
});
flameTester.test('can be loaded', (game) async {
final component = SpaceshipRampBase();
await game.ensureAdd(component);
expect(game.children, contains(component));
});
flameTester.test(
'postSolves disables contact when ball is not on Layer.board',
(game) async {
final ball = _MockBall();
final contact = _MockContact();
when(() => ball.layer).thenReturn(Layer.spaceshipEntranceRamp);
final component = SpaceshipRampBase();
await game.ensureAdd(component);
component.preSolve(ball, contact, _MockManifold());
verify(() => contact.setEnabled(false)).called(1);
},
);
flameTester.test(
'postSolves enables contact when ball is on Layer.board',
(game) async {
final ball = _MockBall();
final contact = _MockContact();
when(() => ball.layer).thenReturn(Layer.board);
final component = SpaceshipRampBase();
await game.ensureAdd(component);
component.preSolve(ball, contact, _MockManifold());
verify(() => contact.setEnabled(true)).called(1);
},
);
});
} }

@ -6,15 +6,20 @@ import 'package:pinball_flame/pinball_flame.dart';
/// {@endtemplate} /// {@endtemplate}
class LayerContactBehavior extends ContactBehavior<BodyComponent> { class LayerContactBehavior extends ContactBehavior<BodyComponent> {
/// {@macro layer_contact_behavior} /// {@macro layer_contact_behavior}
LayerContactBehavior({required Layer layer}) : _layer = layer; LayerContactBehavior({
required Layer layer,
final Layer _layer; bool onBegin = true,
}) {
if (onBegin) {
onBeginContact = (other, _) => _changeLayer(other, layer);
} else {
onEndContact = (other, _) => _changeLayer(other, layer);
}
}
@override void _changeLayer(Object other, Layer layer) {
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
if (other is! Layered) return; if (other is! Layered) return;
if (other.layer == _layer) return; if (other.layer == layer) return;
other.layer = _layer; other.layer = layer;
} }
} }

@ -6,15 +6,20 @@ import 'package:pinball_flame/pinball_flame.dart';
/// {@endtemplate} /// {@endtemplate}
class ZIndexContactBehavior extends ContactBehavior<BodyComponent> { class ZIndexContactBehavior extends ContactBehavior<BodyComponent> {
/// {@macro layer_contact_behavior} /// {@macro layer_contact_behavior}
ZIndexContactBehavior({required int zIndex}) : _zIndex = zIndex; ZIndexContactBehavior({
required int zIndex,
final int _zIndex; bool onBegin = true,
}) {
if (onBegin) {
onBeginContact = (other, _) => _changeZIndex(other, zIndex);
} else {
onEndContact = (other, _) => _changeZIndex(other, zIndex);
}
}
@override void _changeZIndex(Object other, int zIndex) {
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
if (other is! ZIndex) return; if (other is! ZIndex) return;
if (other.zIndex == _zIndex) return; if (other.zIndex == zIndex) return;
other.zIndex = _zIndex; other.zIndex = zIndex;
} }
} }

@ -56,5 +56,23 @@ void main() {
expect(component.layer, newLayer); expect(component.layer, newLayer);
}); });
flameTester.test('endContact changes layer', (game) async {
const oldLayer = Layer.all;
const newLayer = Layer.board;
final behavior = LayerContactBehavior(
layer: newLayer,
onBegin: false,
);
final parent = _TestBodyComponent();
await game.ensureAdd(parent);
await parent.ensureAdd(behavior);
final component = _TestLayeredBodyComponent(layer: oldLayer);
behavior.endContact(component, _MockContact());
expect(component.layer, newLayer);
});
}); });
} }

@ -56,5 +56,20 @@ void main() {
expect(component.zIndex, newIndex); expect(component.zIndex, newIndex);
}); });
flameTester.test('endContact changes zIndex', (game) async {
const oldIndex = 0;
const newIndex = 1;
final behavior = ZIndexContactBehavior(zIndex: newIndex, onBegin: false);
final parent = _TestBodyComponent();
await game.ensureAdd(parent);
await parent.ensureAdd(behavior);
final component = _TestZIndexBodyComponent(zIndex: oldIndex);
behavior.endContact(component, _MockContact());
expect(component.zIndex, newIndex);
});
}); });
} }

Loading…
Cancel
Save