mirror of https://github.com/flutter/pinball.git
parent
431257f831
commit
323756fd73
@ -0,0 +1 @@
|
|||||||
|
export 'ramp_shot_behavior.dart';
|
@ -0,0 +1,28 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template ramp_shot_behavior}
|
||||||
|
/// Detects a [Ball]that enters in the [SpaceshipRamp].
|
||||||
|
///
|
||||||
|
/// The [Ball] can hit with sensor at door or sensor inside, just to recognize
|
||||||
|
/// when if [Ball] comes from out.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class RampShotBehavior extends ContactBehavior<RampSensor> {
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
|
||||||
|
if (other is! Ball) return;
|
||||||
|
switch (parent.type) {
|
||||||
|
case RampSensorType.door:
|
||||||
|
parent.bloc.onDoor(other);
|
||||||
|
break;
|
||||||
|
case RampSensorType.inside:
|
||||||
|
parent.bloc.onInside(other);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
part 'ramp_sensor_state.dart';
|
||||||
|
|
||||||
|
class RampSensorCubit extends Cubit<RampSensorState> {
|
||||||
|
RampSensorCubit() : super(const RampSensorState.initial());
|
||||||
|
|
||||||
|
void onDoor(Ball ball) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: ball,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onInside(Ball ball) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
type: RampSensorType.inside,
|
||||||
|
ball: ball,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
part of 'ramp_sensor_cubit.dart';
|
||||||
|
|
||||||
|
/// Used to know when a [Ball] gets into the [SpaceshipRamp] against every ball
|
||||||
|
/// that crosses the opening.
|
||||||
|
enum RampSensorType {
|
||||||
|
/// Sensor at the entrance of the opening.
|
||||||
|
door,
|
||||||
|
|
||||||
|
/// Sensor inside the [SpaceshipRamp].
|
||||||
|
inside,
|
||||||
|
}
|
||||||
|
|
||||||
|
class RampSensorState {
|
||||||
|
const RampSensorState({
|
||||||
|
required this.type,
|
||||||
|
this.ball,
|
||||||
|
});
|
||||||
|
|
||||||
|
const RampSensorState.initial() : this(type: RampSensorType.door);
|
||||||
|
|
||||||
|
final RampSensorType type;
|
||||||
|
final Ball? ball;
|
||||||
|
|
||||||
|
RampSensorState copyWith({
|
||||||
|
RampSensorType? type,
|
||||||
|
Ball? ball,
|
||||||
|
}) {
|
||||||
|
return RampSensorState(
|
||||||
|
type: type ?? this.type,
|
||||||
|
ball: ball ?? this.ball,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/spaceship_ramp/behavior/behavior.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final assets = [
|
||||||
|
Assets.images.android.ramp.boardOpening.keyName,
|
||||||
|
Assets.images.android.ramp.railingForeground.keyName,
|
||||||
|
Assets.images.android.ramp.railingBackground.keyName,
|
||||||
|
Assets.images.android.ramp.main.keyName,
|
||||||
|
Assets.images.android.ramp.arrow.inactive.keyName,
|
||||||
|
Assets.images.android.ramp.arrow.active1.keyName,
|
||||||
|
Assets.images.android.ramp.arrow.active2.keyName,
|
||||||
|
Assets.images.android.ramp.arrow.active3.keyName,
|
||||||
|
Assets.images.android.ramp.arrow.active4.keyName,
|
||||||
|
Assets.images.android.ramp.arrow.active5.keyName,
|
||||||
|
];
|
||||||
|
|
||||||
|
final flameTester = FlameTester(() => TestGame(assets));
|
||||||
|
|
||||||
|
group(
|
||||||
|
'RampShotBehavior',
|
||||||
|
() {
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
RampShotBehavior(),
|
||||||
|
isA<RampShotBehavior>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
"beginContact with door sensor calls bloc 'onDoor'",
|
||||||
|
(game) async {
|
||||||
|
final ball = Ball(baseColor: Colors.red);
|
||||||
|
final behavior = RampShotBehavior();
|
||||||
|
final bloc = MockRampSensorCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<RampSensorState>.empty(),
|
||||||
|
initialState: RampSensorState(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: ball,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final rampSensor = RampSensor.test(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
bloc: bloc,
|
||||||
|
);
|
||||||
|
final spaceshipRamp = SpaceshipRamp();
|
||||||
|
|
||||||
|
await spaceshipRamp.add(rampSensor);
|
||||||
|
await game.ensureAddAll([spaceshipRamp, ball]);
|
||||||
|
await rampSensor.add(behavior);
|
||||||
|
|
||||||
|
behavior.beginContact(ball, MockContact());
|
||||||
|
|
||||||
|
verify(() => bloc.onDoor(ball)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
"beginContact with inside sensor calls bloc 'onInside'",
|
||||||
|
(game) async {
|
||||||
|
final ball = Ball(baseColor: Colors.red);
|
||||||
|
final behavior = RampShotBehavior();
|
||||||
|
final bloc = MockRampSensorCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<RampSensorState>.empty(),
|
||||||
|
initialState: RampSensorState(
|
||||||
|
type: RampSensorType.inside,
|
||||||
|
ball: ball,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final rampSensor = RampSensor.test(
|
||||||
|
type: RampSensorType.inside,
|
||||||
|
bloc: bloc,
|
||||||
|
);
|
||||||
|
final spaceshipRamp = SpaceshipRamp();
|
||||||
|
|
||||||
|
await spaceshipRamp.add(rampSensor);
|
||||||
|
await game.ensureAddAll([spaceshipRamp, ball]);
|
||||||
|
await rampSensor.add(behavior);
|
||||||
|
|
||||||
|
behavior.beginContact(ball, MockContact());
|
||||||
|
|
||||||
|
verify(() => bloc.onInside(ball)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
// ignore_for_file: prefer_const_constructors
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('RampSensorCubit', () {
|
||||||
|
final ball = Ball(baseColor: Colors.red);
|
||||||
|
|
||||||
|
blocTest<RampSensorCubit, RampSensorState>(
|
||||||
|
'onDoor emits [door]',
|
||||||
|
build: RampSensorCubit.new,
|
||||||
|
act: (bloc) => bloc.onDoor(ball),
|
||||||
|
expect: () => [
|
||||||
|
isA<RampSensorState>()
|
||||||
|
..having((state) => state.type, 'type', RampSensorType.door)
|
||||||
|
..having((state) => state.ball, 'ball', ball),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<RampSensorCubit, RampSensorState>(
|
||||||
|
'onDoor twice emits [door, door]',
|
||||||
|
build: RampSensorCubit.new,
|
||||||
|
act: (bloc) => bloc
|
||||||
|
..onDoor(ball)
|
||||||
|
..onDoor(ball),
|
||||||
|
expect: () => [
|
||||||
|
isA<RampSensorState>()
|
||||||
|
..having((state) => state.type, 'type', RampSensorType.door)
|
||||||
|
..having((state) => state.ball, 'ball', ball),
|
||||||
|
isA<RampSensorState>()
|
||||||
|
..having((state) => state.type, 'type', RampSensorType.door)
|
||||||
|
..having((state) => state.ball, 'ball', ball),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<RampSensorCubit, RampSensorState>(
|
||||||
|
'onInside emits [inside]',
|
||||||
|
build: RampSensorCubit.new,
|
||||||
|
act: (bloc) => bloc.onInside(ball),
|
||||||
|
expect: () => [
|
||||||
|
isA<RampSensorState>()
|
||||||
|
..having((state) => state.type, 'type', RampSensorType.inside)
|
||||||
|
..having((state) => state.ball, 'ball', ball),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<RampSensorCubit, RampSensorState>(
|
||||||
|
'onInside twice emits [inside,inside]',
|
||||||
|
build: RampSensorCubit.new,
|
||||||
|
act: (bloc) => bloc
|
||||||
|
..onInside(ball)
|
||||||
|
..onInside(ball),
|
||||||
|
expect: () => [
|
||||||
|
isA<RampSensorState>()
|
||||||
|
..having((state) => state.type, 'type', RampSensorType.inside)
|
||||||
|
..having((state) => state.ball, 'ball', ball),
|
||||||
|
isA<RampSensorState>()
|
||||||
|
..having((state) => state.type, 'type', RampSensorType.inside)
|
||||||
|
..having((state) => state.ball, 'ball', ball),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
// ignore_for_file: prefer_const_constructors
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('RampSensorState', () {
|
||||||
|
test('same states are different even though they have same content', () {
|
||||||
|
final ball = Ball(baseColor: Colors.red);
|
||||||
|
|
||||||
|
final rampSensorState = RampSensorState(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: ball,
|
||||||
|
);
|
||||||
|
final otherRampSensorState = RampSensorState(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: ball,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
rampSensorState,
|
||||||
|
isNot(equals(otherRampSensorState)),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
rampSensorState.type,
|
||||||
|
equals(otherRampSensorState.type),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
rampSensorState.ball,
|
||||||
|
equals(otherRampSensorState.ball),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('constructor', () {
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
RampSensorState(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: Ball(baseColor: Colors.red),
|
||||||
|
),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('copyWith', () {
|
||||||
|
test(
|
||||||
|
'copies correctly '
|
||||||
|
'when no argument specified',
|
||||||
|
() {
|
||||||
|
final rampSensorState = RampSensorState(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: Ball(baseColor: Colors.red),
|
||||||
|
);
|
||||||
|
|
||||||
|
final copiedRampSensorState = rampSensorState.copyWith();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
copiedRampSensorState.type,
|
||||||
|
equals(rampSensorState.type),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
copiedRampSensorState.ball,
|
||||||
|
equals(rampSensorState.ball),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'copies correctly '
|
||||||
|
'when all arguments specified',
|
||||||
|
() {
|
||||||
|
final ball = Ball(baseColor: Colors.blue);
|
||||||
|
final rampSensorState = RampSensorState(
|
||||||
|
type: RampSensorType.door,
|
||||||
|
ball: Ball(baseColor: Colors.red),
|
||||||
|
);
|
||||||
|
final otherRampSensorState = RampSensorState(
|
||||||
|
type: RampSensorType.inside,
|
||||||
|
ball: ball,
|
||||||
|
);
|
||||||
|
|
||||||
|
final copiedRampSensorState = rampSensorState.copyWith(
|
||||||
|
type: RampSensorType.inside,
|
||||||
|
ball: ball,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
rampSensorState,
|
||||||
|
isNot(equals(otherRampSensorState)),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
copiedRampSensorState.type,
|
||||||
|
equals(otherRampSensorState.type),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
copiedRampSensorState.ball,
|
||||||
|
equals(otherRampSensorState.ball),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in new issue