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