feat: add `GoogleRollovers` (#407)

* feat: add google rollovers

* fix: spelling

* refactor: move zIndex to parent

* chore: remove unnecessary wrapper

* fix: CI

* refactor: PR revisions

* refactor: suggestions

* style: remove parentheses

Co-authored-by: Jorge Coca <jorgecoca@users.noreply.github.com>
pull/426/head
Allison Ryan 2 years ago committed by GitHub
parent ea33c1c889
commit 48c5c80b38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,7 +6,7 @@ export 'dino_desert/dino_desert.dart';
export 'drain/drain.dart';
export 'flutter_forest/flutter_forest.dart';
export 'game_bloc_status_listener.dart';
export 'google_word/google_word.dart';
export 'google_gallery/google_gallery.dart';
export 'launcher.dart';
export 'multiballs/multiballs.dart';
export 'multipliers/multipliers.dart';

@ -0,0 +1,24 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Adds a [GameBonus.googleWord] when all [GoogleLetter]s are activated.
class GoogleWordBonusBehavior extends Component {
@override
Future<void> onLoad() async {
await super.onLoad();
await add(
FlameBlocListener<GoogleWordCubit, GoogleWordState>(
listenWhen: (_, state) => state.letterSpriteStates.values
.every((element) => element == GoogleLetterSpriteState.lit),
onNewState: (state) {
readBloc<GameBloc, GameState>()
.add(const BonusActivated(GameBonus.googleWord));
readBloc<GoogleWordCubit, GoogleWordState>().onBonusAwarded();
},
),
);
}
}

@ -0,0 +1,47 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flutter/material.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/google_gallery/behaviors/behaviors.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template google_gallery}
/// Middle section of the board containing the [GoogleWord] and the
/// [GoogleRollover]s.
/// {@endtemplate}
class GoogleGallery extends Component with ZIndex {
/// {@macro google_gallery}
GoogleGallery()
: super(
children: [
FlameBlocProvider<GoogleWordCubit, GoogleWordState>(
create: GoogleWordCubit.new,
children: [
GoogleRollover(
side: BoardSide.right,
children: [
ScoringContactBehavior(points: Points.fiveThousand),
],
),
GoogleRollover(
side: BoardSide.left,
children: [
ScoringContactBehavior(points: Points.fiveThousand),
],
),
GoogleWord(position: Vector2(-4.45, 1.8)),
GoogleWordBonusBehavior(),
],
),
],
) {
zIndex = ZIndexes.decal;
}
/// Creates a [GoogleGallery] without any children.
///
/// This can be used for testing [GoogleGallery]'s behaviors in isolation.
@visibleForTesting
GoogleGallery.test();
}

@ -1,29 +0,0 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Adds a [GameBonus.googleWord] when all [GoogleLetter]s are activated.
class GoogleWordBonusBehavior extends Component
with ParentIsA<GoogleWord>, FlameBlocReader<GameBloc, GameState> {
@override
void onMount() {
super.onMount();
final googleLetters = parent.children.whereType<GoogleLetter>();
for (final letter in googleLetters) {
letter.bloc.stream.listen((_) {
final achievedBonus = googleLetters
.every((letter) => letter.bloc.state == GoogleLetterState.lit);
if (achievedBonus) {
bloc.add(const BonusActivated(GameBonus.googleWord));
for (final letter in googleLetters) {
letter.bloc.onReset();
}
}
});
}
}
}

@ -1,52 +0,0 @@
import 'package:flame/components.dart';
import 'package:flutter/material.dart';
import 'package:pinball/game/behaviors/scoring_behavior.dart';
import 'package:pinball/game/components/google_word/behaviors/behaviors.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template google_word}
/// Loads all [GoogleLetter]s to compose a [GoogleWord].
/// {@endtemplate}
class GoogleWord extends Component with ZIndex {
/// {@macro google_word}
GoogleWord({
required Vector2 position,
}) : super(
children: [
GoogleLetter(
0,
children: [ScoringContactBehavior(points: Points.fiveThousand)],
)..initialPosition = position + Vector2(-13.1, 1.72),
GoogleLetter(
1,
children: [ScoringContactBehavior(points: Points.fiveThousand)],
)..initialPosition = position + Vector2(-8.33, -0.75),
GoogleLetter(
2,
children: [ScoringContactBehavior(points: Points.fiveThousand)],
)..initialPosition = position + Vector2(-2.88, -1.85),
GoogleLetter(
3,
children: [ScoringContactBehavior(points: Points.fiveThousand)],
)..initialPosition = position + Vector2(2.88, -1.85),
GoogleLetter(
4,
children: [ScoringContactBehavior(points: Points.fiveThousand)],
)..initialPosition = position + Vector2(8.33, -0.75),
GoogleLetter(
5,
children: [ScoringContactBehavior(points: Points.fiveThousand)],
)..initialPosition = position + Vector2(13.1, 1.72),
GoogleWordBonusBehavior(),
],
) {
zIndex = ZIndexes.decal;
}
/// Creates a [GoogleWord] without any children.
///
/// This can be used for testing [GoogleWord]'s behaviors in isolation.
@visibleForTesting
GoogleWord.test();
}

@ -118,6 +118,10 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.googleWord.letter5.dimmed.keyName),
images.load(components.Assets.images.googleWord.letter6.lit.keyName),
images.load(components.Assets.images.googleWord.letter6.dimmed.keyName),
images.load(components.Assets.images.googleRollover.left.decal.keyName),
images.load(components.Assets.images.googleRollover.left.pin.keyName),
images.load(components.Assets.images.googleRollover.right.decal.keyName),
images.load(components.Assets.images.googleRollover.right.pin.keyName),
images.load(components.Assets.images.multiball.lit.keyName),
images.load(components.Assets.images.multiball.dimmed.keyName),
images.load(components.Assets.images.multiplier.x2.lit.keyName),

@ -114,7 +114,7 @@ class PinballGame extends PinballForge2DGame
shareRepository: shareRepository,
entries: _entries,
),
GoogleWord(position: Vector2(-4.45, 1.8)),
GoogleGallery(),
Multipliers(),
Multiballs(),
SkillShot(

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -32,6 +32,8 @@ class $AssetsImagesGen {
$AssetsImagesFlapperGen get flapper => const $AssetsImagesFlapperGen();
$AssetsImagesFlipperGen get flipper => const $AssetsImagesFlipperGen();
$AssetsImagesGoogleRolloverGen get googleRollover =>
const $AssetsImagesGoogleRolloverGen();
$AssetsImagesGoogleWordGen get googleWord =>
const $AssetsImagesGoogleWordGen();
$AssetsImagesKickerGen get kicker => const $AssetsImagesKickerGen();
@ -180,6 +182,15 @@ class $AssetsImagesFlipperGen {
const AssetGenImage('assets/images/flipper/right.png');
}
class $AssetsImagesGoogleRolloverGen {
const $AssetsImagesGoogleRolloverGen();
$AssetsImagesGoogleRolloverLeftGen get left =>
const $AssetsImagesGoogleRolloverLeftGen();
$AssetsImagesGoogleRolloverRightGen get right =>
const $AssetsImagesGoogleRolloverRightGen();
}
class $AssetsImagesGoogleWordGen {
const $AssetsImagesGoogleWordGen();
@ -434,6 +445,24 @@ class $AssetsImagesDinoAnimatronicGen {
const AssetGenImage('assets/images/dino/animatronic/mouth.png');
}
class $AssetsImagesGoogleRolloverLeftGen {
const $AssetsImagesGoogleRolloverLeftGen();
AssetGenImage get decal =>
const AssetGenImage('assets/images/google_rollover/left/decal.png');
AssetGenImage get pin =>
const AssetGenImage('assets/images/google_rollover/left/pin.png');
}
class $AssetsImagesGoogleRolloverRightGen {
const $AssetsImagesGoogleRolloverRightGen();
AssetGenImage get decal =>
const AssetGenImage('assets/images/google_rollover/right/decal.png');
AssetGenImage get pin =>
const AssetGenImage('assets/images/google_rollover/right/pin.png');
}
class $AssetsImagesGoogleWordLetter1Gen {
const $AssetsImagesGoogleWordLetter1Gen();

@ -17,7 +17,9 @@ export 'dino_walls.dart';
export 'error_component.dart';
export 'flapper/flapper.dart';
export 'flipper/flipper.dart';
export 'google_letter/google_letter.dart';
export 'google_letter.dart';
export 'google_rollover/google_rollover.dart';
export 'google_word/google_word.dart';
export 'initial_position.dart';
export 'joint_anchor.dart';
export 'kicker/kicker.dart';

@ -0,0 +1,88 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
enum GoogleLetterSpriteState {
lit,
dimmed,
}
/// {@template google_letter}
/// Circular decal that represents a letter in "GOOGLE" for a given index.
/// {@endtemplate}
class GoogleLetter extends SpriteGroupComponent<GoogleLetterSpriteState>
with HasGameRef, FlameBlocListenable<GoogleWordCubit, GoogleWordState> {
/// {@macro google_letter}
GoogleLetter(int index)
: _litAssetPath = _spritePaths[index][GoogleLetterSpriteState.lit]!,
_dimmedAssetPath = _spritePaths[index][GoogleLetterSpriteState.dimmed]!,
_index = index,
super(anchor: Anchor.center);
final String _litAssetPath;
final String _dimmedAssetPath;
final int _index;
@override
bool listenWhen(GoogleWordState previousState, GoogleWordState newState) {
return previousState.letterSpriteStates[_index] !=
newState.letterSpriteStates[_index];
}
@override
void onNewState(GoogleWordState state) =>
current = state.letterSpriteStates[_index];
@override
Future<void> onLoad() async {
await super.onLoad();
final sprites = {
GoogleLetterSpriteState.lit: Sprite(
gameRef.images.fromCache(_litAssetPath),
),
GoogleLetterSpriteState.dimmed: Sprite(
gameRef.images.fromCache(_dimmedAssetPath),
),
};
this.sprites = sprites;
current = readBloc<GoogleWordCubit, GoogleWordState>()
.state
.letterSpriteStates[_index];
size = sprites[current]!.originalSize / 10;
}
}
final _spritePaths = <Map<GoogleLetterSpriteState, String>>[
{
GoogleLetterSpriteState.lit: Assets.images.googleWord.letter1.lit.keyName,
GoogleLetterSpriteState.dimmed:
Assets.images.googleWord.letter1.dimmed.keyName,
},
{
GoogleLetterSpriteState.lit: Assets.images.googleWord.letter2.lit.keyName,
GoogleLetterSpriteState.dimmed:
Assets.images.googleWord.letter2.dimmed.keyName,
},
{
GoogleLetterSpriteState.lit: Assets.images.googleWord.letter3.lit.keyName,
GoogleLetterSpriteState.dimmed:
Assets.images.googleWord.letter3.dimmed.keyName,
},
{
GoogleLetterSpriteState.lit: Assets.images.googleWord.letter4.lit.keyName,
GoogleLetterSpriteState.dimmed:
Assets.images.googleWord.letter4.dimmed.keyName,
},
{
GoogleLetterSpriteState.lit: Assets.images.googleWord.letter5.lit.keyName,
GoogleLetterSpriteState.dimmed:
Assets.images.googleWord.letter5.dimmed.keyName,
},
{
GoogleLetterSpriteState.lit: Assets.images.googleWord.letter6.lit.keyName,
GoogleLetterSpriteState.dimmed:
Assets.images.googleWord.letter6.dimmed.keyName,
},
];

@ -1,15 +0,0 @@
import 'package:bloc/bloc.dart';
part 'google_letter_state.dart';
class GoogleLetterCubit extends Cubit<GoogleLetterState> {
GoogleLetterCubit() : super(GoogleLetterState.dimmed);
void onBallContacted() {
emit(GoogleLetterState.lit);
}
void onReset() {
emit(GoogleLetterState.dimmed);
}
}

@ -1,6 +0,0 @@
part of 'google_letter_cubit.dart';
enum GoogleLetterState {
lit,
dimmed,
}

@ -1,133 +0,0 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/google_letter/behaviors/behaviors.dart';
import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/google_letter_cubit.dart';
final _spritePaths = <Map<GoogleLetterState, String>>[
{
GoogleLetterState.lit: Assets.images.googleWord.letter1.lit.keyName,
GoogleLetterState.dimmed: Assets.images.googleWord.letter1.dimmed.keyName,
},
{
GoogleLetterState.lit: Assets.images.googleWord.letter2.lit.keyName,
GoogleLetterState.dimmed: Assets.images.googleWord.letter2.dimmed.keyName,
},
{
GoogleLetterState.lit: Assets.images.googleWord.letter3.lit.keyName,
GoogleLetterState.dimmed: Assets.images.googleWord.letter3.dimmed.keyName,
},
{
GoogleLetterState.lit: Assets.images.googleWord.letter4.lit.keyName,
GoogleLetterState.dimmed: Assets.images.googleWord.letter4.dimmed.keyName,
},
{
GoogleLetterState.lit: Assets.images.googleWord.letter5.lit.keyName,
GoogleLetterState.dimmed: Assets.images.googleWord.letter5.dimmed.keyName,
},
{
GoogleLetterState.lit: Assets.images.googleWord.letter6.lit.keyName,
GoogleLetterState.dimmed: Assets.images.googleWord.letter6.dimmed.keyName,
},
];
/// {@template google_letter}
/// Circular sensor that represents a letter in "GOOGLE" for a given index.
/// {@endtemplate}
class GoogleLetter extends BodyComponent with InitialPosition {
/// {@macro google_letter}
GoogleLetter(
int index, {
Iterable<Component>? children,
}) : this._(
index,
bloc: GoogleLetterCubit(),
children: children,
);
GoogleLetter._(
int index, {
required this.bloc,
Iterable<Component>? children,
}) : super(
children: [
_GoogleLetterSpriteGroupComponent(
litAssetPath: _spritePaths[index][GoogleLetterState.lit]!,
dimmedAssetPath: _spritePaths[index][GoogleLetterState.dimmed]!,
current: bloc.state,
),
GoogleLetterBallContactBehavior(),
...?children,
],
renderBody: false,
);
/// Creates a [GoogleLetter] without any children.
///
/// This can be used for testing [GoogleLetter]'s behaviors in isolation.
@visibleForTesting
GoogleLetter.test({
required this.bloc,
});
final GoogleLetterCubit bloc;
@override
void onRemove() {
bloc.close();
super.onRemove();
}
@override
Body createBody() {
final shape = CircleShape()..radius = 1.85;
final fixtureDef = FixtureDef(
shape,
isSensor: true,
);
final bodyDef = BodyDef(
position: initialPosition,
userData: this,
);
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class _GoogleLetterSpriteGroupComponent
extends SpriteGroupComponent<GoogleLetterState>
with HasGameRef, ParentIsA<GoogleLetter> {
_GoogleLetterSpriteGroupComponent({
required String litAssetPath,
required String dimmedAssetPath,
required GoogleLetterState current,
}) : _litAssetPath = litAssetPath,
_dimmedAssetPath = dimmedAssetPath,
super(
anchor: Anchor.center,
current: current,
);
final String _litAssetPath;
final String _dimmedAssetPath;
@override
Future<void> onLoad() async {
await super.onLoad();
parent.bloc.stream.listen((state) => current = state);
final sprites = {
GoogleLetterState.lit: Sprite(
gameRef.images.fromCache(_litAssetPath),
),
GoogleLetterState.dimmed: Sprite(
gameRef.images.fromCache(_dimmedAssetPath),
),
};
this.sprites = sprites;
size = sprites[current]!.originalSize / 10;
}
}

@ -1,12 +1,15 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class GoogleLetterBallContactBehavior extends ContactBehavior<GoogleLetter> {
class GoogleRolloverBallContactBehavior
extends ContactBehavior<GoogleRollover> {
@override
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
if (other is! Ball) return;
parent.bloc.onBallContacted();
readBloc<GoogleWordCubit, GoogleWordState>().onRolloverContacted();
parent.firstChild<SpriteAnimationComponent>()?.playing = true;
}
}

@ -0,0 +1,113 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/google_rollover/behaviors/behaviors.dart';
/// {@template google_rollover}
/// Rollover that lights up [GoogleLetter]s.
/// {@endtemplate}
class GoogleRollover extends BodyComponent {
/// {@macro google_rollover}
GoogleRollover({
required BoardSide side,
Iterable<Component>? children,
}) : _side = side,
super(
renderBody: false,
children: [
GoogleRolloverBallContactBehavior(),
_RolloverDecalSpriteComponent(side: side),
_PinSpriteAnimationComponent(side: side),
...?children,
],
);
final BoardSide _side;
@override
Body createBody() {
final shape = PolygonShape()
..setAsBox(
0.1,
3.4,
Vector2(_side.isLeft ? -14.8 : 5.9, -11),
0.19 * _side.direction,
);
final fixtureDef = FixtureDef(shape, isSensor: true);
return world.createBody(BodyDef())..createFixture(fixtureDef);
}
}
class _RolloverDecalSpriteComponent extends SpriteComponent with HasGameRef {
_RolloverDecalSpriteComponent({required BoardSide side})
: _side = side,
super(
anchor: Anchor.center,
position: Vector2(side.isLeft ? -14.8 : 5.9, -11),
angle: 0.18 * side.direction,
);
final BoardSide _side;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = Sprite(
gameRef.images.fromCache(
(_side.isLeft)
? Assets.images.googleRollover.left.decal.keyName
: Assets.images.googleRollover.right.decal.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 20;
}
}
class _PinSpriteAnimationComponent extends SpriteAnimationComponent
with HasGameRef {
_PinSpriteAnimationComponent({required BoardSide side})
: _side = side,
super(
anchor: Anchor.center,
position: Vector2(side.isLeft ? -14.9 : 5.95, -11),
angle: 0,
playing: false,
);
final BoardSide _side;
@override
Future<void> onLoad() async {
await super.onLoad();
final spriteSheet = gameRef.images.fromCache(
_side.isLeft
? Assets.images.googleRollover.left.pin.keyName
: Assets.images.googleRollover.right.pin.keyName,
);
const amountPerRow = 3;
const amountPerColumn = 1;
final textureSize = Vector2(
spriteSheet.width / amountPerRow,
spriteSheet.height / amountPerColumn,
);
size = textureSize / 10;
animation = SpriteAnimation.fromFrameData(
spriteSheet,
SpriteAnimationData.sequenced(
amount: amountPerRow * amountPerColumn,
amountPerRow: amountPerRow,
stepTime: 1 / 24,
textureSize: textureSize,
loop: false,
),
)..onComplete = () {
animation?.reset();
playing = false;
};
}
}

@ -0,0 +1,30 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:pinball_components/pinball_components.dart';
part 'google_word_state.dart';
class GoogleWordCubit extends Cubit<GoogleWordState> {
GoogleWordCubit() : super(GoogleWordState.initial());
static const _lettersInGoogle = 6;
int _lastLitLetter = 0;
void onRolloverContacted() {
final spriteStatesMap = {...state.letterSpriteStates};
if (_lastLitLetter < _lettersInGoogle) {
spriteStatesMap.update(
_lastLitLetter,
(_) => GoogleLetterSpriteState.lit,
);
emit(GoogleWordState(letterSpriteStates: spriteStatesMap));
_lastLitLetter++;
}
}
void onBonusAwarded() {
emit(GoogleWordState.initial());
_lastLitLetter = 0;
}
}

@ -0,0 +1,17 @@
part of 'google_word_cubit.dart';
class GoogleWordState extends Equatable {
const GoogleWordState({required this.letterSpriteStates});
GoogleWordState.initial()
: this(
letterSpriteStates: {
for (var i = 0; i <= 5; i++) i: GoogleLetterSpriteState.dimmed
},
);
final Map<int, GoogleLetterSpriteState> letterSpriteStates;
@override
List<Object> get props => [...letterSpriteStates.values];
}

@ -0,0 +1,24 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
export 'cubit/google_word_cubit.dart';
/// {@template google_word}
/// Loads all [GoogleLetter]s to compose a [GoogleWord].
/// {@endtemplate}
class GoogleWord extends PositionComponent {
/// {@macro google_word}
GoogleWord({
required Vector2 position,
}) : super(
position: position,
children: [
GoogleLetter(0)..position = Vector2(-13.1, 1.72),
GoogleLetter(1)..position = Vector2(-8.33, -0.75),
GoogleLetter(2)..position = Vector2(-2.88, -1.85),
GoogleLetter(3)..position = Vector2(2.88, -1.85),
GoogleLetter(4)..position = Vector2(8.33, -0.75),
GoogleLetter(5)..position = Vector2(13.1, 1.72),
],
);
}

@ -81,6 +81,8 @@ flutter:
- assets/images/google_word/letter4/
- assets/images/google_word/letter5/
- assets/images/google_word/letter6/
- assets/images/google_rollover/left/
- assets/images/google_rollover/right/
- assets/images/signpost/
- assets/images/multiball/
- assets/images/multiplier/x2/

@ -1,55 +0,0 @@
// ignore_for_file: cascade_invocations
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.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/google_letter/behaviors/behaviors.dart';
import '../../../../helpers/helpers.dart';
class _MockGoogleLetterCubit extends Mock implements GoogleLetterCubit {}
class _MockBall extends Mock implements Ball {}
class _MockContact extends Mock implements Contact {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new);
group(
'GoogleLetterBallContactBehavior',
() {
test('can be instantiated', () {
expect(
GoogleLetterBallContactBehavior(),
isA<GoogleLetterBallContactBehavior>(),
);
});
flameTester.test(
'beginContact emits onBallContacted when contacts with a ball',
(game) async {
final behavior = GoogleLetterBallContactBehavior();
final bloc = _MockGoogleLetterCubit();
whenListen(
bloc,
const Stream<GoogleLetterState>.empty(),
initialState: GoogleLetterState.lit,
);
final googleLetter = GoogleLetter.test(bloc: bloc);
await googleLetter.add(behavior);
await game.ensureAdd(googleLetter);
behavior.beginContact(_MockBall(), _MockContact());
verify(googleLetter.bloc.onBallContacted).called(1);
},
);
},
);
}

@ -1,24 +0,0 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
void main() {
group(
'GoogleLetterCubit',
() {
blocTest<GoogleLetterCubit, GoogleLetterState>(
'onBallContacted emits active',
build: GoogleLetterCubit.new,
act: (bloc) => bloc.onBallContacted(),
expect: () => [GoogleLetterState.lit],
);
blocTest<GoogleLetterCubit, GoogleLetterState>(
'onReset emits inactive',
build: GoogleLetterCubit.new,
act: (bloc) => bloc.onReset(),
expect: () => [GoogleLetterState.dimmed],
);
},
);
}

@ -1,145 +0,0 @@
// ignore_for_file: cascade_invocations
import 'package:bloc_test/bloc_test.dart';
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.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/google_letter/behaviors/behaviors.dart';
import '../../../helpers/helpers.dart';
class _MockGoogleLetterCubit extends Mock implements GoogleLetterCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.googleWord.letter1.lit.keyName,
Assets.images.googleWord.letter1.dimmed.keyName,
Assets.images.googleWord.letter2.lit.keyName,
Assets.images.googleWord.letter2.dimmed.keyName,
Assets.images.googleWord.letter3.lit.keyName,
Assets.images.googleWord.letter3.dimmed.keyName,
Assets.images.googleWord.letter4.lit.keyName,
Assets.images.googleWord.letter4.dimmed.keyName,
Assets.images.googleWord.letter5.lit.keyName,
Assets.images.googleWord.letter5.dimmed.keyName,
Assets.images.googleWord.letter6.lit.keyName,
Assets.images.googleWord.letter6.dimmed.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
group('Google Letter', () {
flameTester.test(
'0th loads correctly',
(game) async {
final googleLetter = GoogleLetter(0);
await game.ready();
await game.ensureAdd(googleLetter);
expect(game.contains(googleLetter), isTrue);
},
);
flameTester.test(
'1st loads correctly',
(game) async {
final googleLetter = GoogleLetter(1);
await game.ready();
await game.ensureAdd(googleLetter);
expect(game.contains(googleLetter), isTrue);
},
);
flameTester.test(
'2nd loads correctly',
(game) async {
final googleLetter = GoogleLetter(2);
await game.ready();
await game.ensureAdd(googleLetter);
expect(game.contains(googleLetter), isTrue);
},
);
flameTester.test(
'3d loads correctly',
(game) async {
final googleLetter = GoogleLetter(3);
await game.ready();
await game.ensureAdd(googleLetter);
expect(game.contains(googleLetter), isTrue);
},
);
flameTester.test(
'4th loads correctly',
(game) async {
final googleLetter = GoogleLetter(4);
await game.ready();
await game.ensureAdd(googleLetter);
expect(game.contains(googleLetter), isTrue);
},
);
flameTester.test(
'5th loads correctly',
(game) async {
final googleLetter = GoogleLetter(5);
await game.ready();
await game.ensureAdd(googleLetter);
expect(game.contains(googleLetter), isTrue);
},
);
test('throws error when index out of range', () {
expect(() => GoogleLetter(-1), throwsA(isA<RangeError>()));
expect(() => GoogleLetter(6), throwsA(isA<RangeError>()));
});
flameTester.test('closes bloc when removed', (game) async {
final bloc = _MockGoogleLetterCubit();
whenListen(
bloc,
const Stream<GoogleLetterState>.empty(),
initialState: GoogleLetterState.lit,
);
when(bloc.close).thenAnswer((_) async {});
final googleLetter = GoogleLetter.test(bloc: bloc);
await game.ensureAdd(googleLetter);
game.remove(googleLetter);
await game.ready();
verify(bloc.close).called(1);
});
group('adds', () {
flameTester.test('new children', (game) async {
final component = Component();
final googleLetter = GoogleLetter(
1,
children: [component],
);
await game.ensureAdd(googleLetter);
expect(googleLetter.children, contains(component));
});
flameTester.test('a GoogleLetterBallContactBehavior', (game) async {
final googleLetter = GoogleLetter(0);
await game.ensureAdd(googleLetter);
expect(
googleLetter.children
.whereType<GoogleLetterBallContactBehavior>()
.single,
isNotNull,
);
});
});
});
}

@ -0,0 +1,159 @@
// ignore_for_file: cascade_invocations
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.googleWord.letter1.lit.keyName,
Assets.images.googleWord.letter1.dimmed.keyName,
Assets.images.googleWord.letter2.lit.keyName,
Assets.images.googleWord.letter2.dimmed.keyName,
Assets.images.googleWord.letter3.lit.keyName,
Assets.images.googleWord.letter3.dimmed.keyName,
Assets.images.googleWord.letter4.lit.keyName,
Assets.images.googleWord.letter4.dimmed.keyName,
Assets.images.googleWord.letter5.lit.keyName,
Assets.images.googleWord.letter5.dimmed.keyName,
Assets.images.googleWord.letter6.lit.keyName,
Assets.images.googleWord.letter6.dimmed.keyName,
]);
}
Future<void> pump(GoogleLetter child) async {
await ensureAdd(
FlameBlocProvider<GoogleWordCubit, GoogleWordState>.value(
value: GoogleWordCubit(),
children: [child],
),
);
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group('Google Letter', () {
test('can be instantiated', () {
expect(GoogleLetter(0), isA<GoogleLetter>());
});
flameTester.test(
'0th loads correctly',
(game) async {
final googleLetter = GoogleLetter(0);
await game.pump(googleLetter);
expect(game.descendants().contains(googleLetter), isTrue);
},
);
flameTester.test(
'1st loads correctly',
(game) async {
final googleLetter = GoogleLetter(1);
await game.pump(googleLetter);
expect(game.descendants().contains(googleLetter), isTrue);
},
);
flameTester.test(
'2nd loads correctly',
(game) async {
final googleLetter = GoogleLetter(2);
await game.pump(googleLetter);
expect(game.descendants().contains(googleLetter), isTrue);
},
);
flameTester.test(
'3d loads correctly',
(game) async {
final googleLetter = GoogleLetter(3);
await game.pump(googleLetter);
expect(game.descendants().contains(googleLetter), isTrue);
},
);
flameTester.test(
'4th loads correctly',
(game) async {
final googleLetter = GoogleLetter(4);
await game.pump(googleLetter);
expect(game.descendants().contains(googleLetter), isTrue);
},
);
flameTester.test(
'5th loads correctly',
(game) async {
final googleLetter = GoogleLetter(5);
await game.pump(googleLetter);
expect(game.descendants().contains(googleLetter), isTrue);
},
);
test('throws error when index out of range', () {
expect(() => GoogleLetter(-1), throwsA(isA<RangeError>()));
expect(() => GoogleLetter(6), throwsA(isA<RangeError>()));
});
group('sprite', () {
const firstLetterLitState = GoogleWordState(
letterSpriteStates: {
0: GoogleLetterSpriteState.lit,
1: GoogleLetterSpriteState.dimmed,
2: GoogleLetterSpriteState.dimmed,
3: GoogleLetterSpriteState.dimmed,
4: GoogleLetterSpriteState.dimmed,
5: GoogleLetterSpriteState.dimmed,
},
);
flameTester.test(
"listens when its index's state changes",
(game) async {
final googleLetter = GoogleLetter(0);
await game.pump(googleLetter);
expect(
googleLetter.listenWhen(
GoogleWordState.initial(),
firstLetterLitState,
),
isTrue,
);
},
);
flameTester.test(
'changes current sprite onNewState',
(game) async {
final googleLetter = GoogleLetter(0);
await game.pump(googleLetter);
final originalSprite = googleLetter.current;
googleLetter.onNewState(firstLetterLitState);
await game.ready();
final newSprite = googleLetter.current;
expect(newSprite != originalSprite, isTrue);
},
);
});
});
}

@ -0,0 +1,81 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.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/google_rollover/behaviors/behaviors.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.googleRollover.left.decal.keyName,
Assets.images.googleRollover.left.pin.keyName,
]);
}
Future<void> pump(
GoogleRollover child, {
GoogleWordCubit? bloc,
}) async {
// Not needed once https://github.com/flame-engine/flame/issues/1607
// is fixed
await onLoad();
await ensureAdd(
FlameBlocProvider<GoogleWordCubit, GoogleWordState>.value(
value: bloc ?? GoogleWordCubit(),
children: [child],
),
);
}
}
class _MockBall extends Mock implements Ball {}
class _MockContact extends Mock implements Contact {}
class _MockGoogleWordCubit extends Mock implements GoogleWordCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group(
'GoogleRolloverBallContactBehavior',
() {
test('can be instantiated', () {
expect(
GoogleRolloverBallContactBehavior(),
isA<GoogleRolloverBallContactBehavior>(),
);
});
flameTester.testGameWidget(
'beginContact animates pin and calls onRolloverContacted '
'when contacts with a ball',
setUp: (game, tester) async {
final behavior = GoogleRolloverBallContactBehavior();
final bloc = _MockGoogleWordCubit();
final googleRollover = GoogleRollover(side: BoardSide.left);
await googleRollover.add(behavior);
await game.pump(googleRollover, bloc: bloc);
behavior.beginContact(_MockBall(), _MockContact());
await tester.pump();
expect(
googleRollover.firstChild<SpriteAnimationComponent>()!.playing,
isTrue,
);
verify(bloc.onRolloverContacted).called(1);
},
);
},
);
}

@ -0,0 +1,82 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/google_rollover/behaviors/behaviors.dart';
import '../../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.googleRollover.left.decal.keyName,
Assets.images.googleRollover.left.pin.keyName,
Assets.images.googleRollover.right.decal.keyName,
Assets.images.googleRollover.right.pin.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
group('GoogleRollover', () {
test('can be instantiated', () {
expect(
GoogleRollover(side: BoardSide.left),
isA<GoogleRollover>(),
);
});
flameTester.test('left loads correctly', (game) async {
final googleRollover = GoogleRollover(side: BoardSide.left);
await game.ensureAdd(googleRollover);
expect(game.contains(googleRollover), isTrue);
});
flameTester.test('right loads correctly', (game) async {
final googleRollover = GoogleRollover(side: BoardSide.right);
await game.ensureAdd(googleRollover);
expect(game.contains(googleRollover), isTrue);
});
group('adds', () {
flameTester.test('new children', (game) async {
final component = Component();
final googleRollover = GoogleRollover(
side: BoardSide.left,
children: [component],
);
await game.ensureAdd(googleRollover);
expect(googleRollover.children, contains(component));
});
flameTester.test('a GoogleRolloverBallContactBehavior', (game) async {
final googleRollover = GoogleRollover(side: BoardSide.left);
await game.ensureAdd(googleRollover);
expect(
googleRollover.children
.whereType<GoogleRolloverBallContactBehavior>()
.single,
isNotNull,
);
});
});
flameTester.test(
'pin stops animating after animation completes',
(game) async {
final googleRollover = GoogleRollover(side: BoardSide.left);
await game.ensureAdd(googleRollover);
final pinSpriteAnimationComponent =
googleRollover.firstChild<SpriteAnimationComponent>()!;
pinSpriteAnimationComponent.playing = true;
game.update(
pinSpriteAnimationComponent.animation!.totalDuration() + 0.1,
);
expect(pinSpriteAnimationComponent.playing, isFalse);
},
);
});
}

@ -0,0 +1,35 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
void main() {
group(
'GoogleWordCubit',
() {
blocTest<GoogleWordCubit, GoogleWordState>(
'onRolloverContacted emits first letter lit',
build: GoogleWordCubit.new,
act: (bloc) => bloc.onRolloverContacted(),
expect: () => [
const GoogleWordState(
letterSpriteStates: {
0: GoogleLetterSpriteState.lit,
1: GoogleLetterSpriteState.dimmed,
2: GoogleLetterSpriteState.dimmed,
3: GoogleLetterSpriteState.dimmed,
4: GoogleLetterSpriteState.dimmed,
5: GoogleLetterSpriteState.dimmed,
},
),
],
);
blocTest<GoogleWordCubit, GoogleWordState>(
'onBonusAwarded emits initial state',
build: GoogleWordCubit.new,
act: (bloc) => bloc.onBonusAwarded(),
expect: () => [GoogleWordState.initial()],
);
},
);
}

@ -0,0 +1,58 @@
// ignore_for_file: prefer_const_constructors
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
void main() {
group('GoogleWordState', () {
test('supports value equality', () {
expect(
GoogleWordState(
letterSpriteStates: const {
0: GoogleLetterSpriteState.dimmed,
1: GoogleLetterSpriteState.dimmed,
2: GoogleLetterSpriteState.dimmed,
3: GoogleLetterSpriteState.dimmed,
4: GoogleLetterSpriteState.dimmed,
5: GoogleLetterSpriteState.dimmed,
},
),
equals(
GoogleWordState(
letterSpriteStates: const {
0: GoogleLetterSpriteState.dimmed,
1: GoogleLetterSpriteState.dimmed,
2: GoogleLetterSpriteState.dimmed,
3: GoogleLetterSpriteState.dimmed,
4: GoogleLetterSpriteState.dimmed,
5: GoogleLetterSpriteState.dimmed,
},
),
),
);
});
group('constructor', () {
test('can be instantiated', () {
expect(
const GoogleWordState(letterSpriteStates: {}),
isNotNull,
);
});
test('initial has all dimmed sprite states', () {
const initialState = GoogleWordState(
letterSpriteStates: {
0: GoogleLetterSpriteState.dimmed,
1: GoogleLetterSpriteState.dimmed,
2: GoogleLetterSpriteState.dimmed,
3: GoogleLetterSpriteState.dimmed,
4: GoogleLetterSpriteState.dimmed,
5: GoogleLetterSpriteState.dimmed,
},
);
expect(GoogleWordState.initial(), equals(initialState));
});
});
});
}

@ -4,8 +4,6 @@ import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/components/google_word/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
@ -28,10 +26,10 @@ class _TestGame extends Forge2DGame {
]);
}
Future<void> pump(GoogleWord child, {GameBloc? gameBloc}) {
return ensureAdd(
FlameBlocProvider<GameBloc, GameState>.value(
value: gameBloc ?? GameBloc(),
Future<void> pump(GoogleWord child) async {
await ensureAdd(
FlameBlocProvider<GoogleWordCubit, GoogleWordState>.value(
value: GoogleWordCubit(),
children: [child],
),
);
@ -44,25 +42,21 @@ void main() {
final flameTester = FlameTester(_TestGame.new);
group('GoogleWord', () {
test('can be instantiated', () {
expect(GoogleWord(position: Vector2.zero()), isA<GoogleWord>());
});
flameTester.test(
'loads the letters correctly',
'loads letters correctly',
(game) async {
const word = 'Google';
final googleWord = GoogleWord(position: Vector2.zero());
await game.pump(googleWord);
final letters = googleWord.children.whereType<GoogleLetter>();
expect(letters.length, equals(word.length));
expect(
googleWord.children.whereType<GoogleLetter>().length,
equals(6),
);
},
);
flameTester.test('adds a GoogleWordBonusBehavior', (game) async {
final googleWord = GoogleWord(position: Vector2.zero());
await game.pump(googleWord);
expect(
googleWord.children.whereType<GoogleWordBonusBehavior>().single,
isNotNull,
);
});
});
}

@ -31,7 +31,7 @@ void main() {
);
});
test('initial is idle with mouth closed', () {
test('initial is dimmed and not blinking', () {
const initialState = SkillShotState(
spriteState: SkillShotSpriteState.dimmed,
isBlinking: false,
@ -45,13 +45,13 @@ void main() {
'copies correctly '
'when no argument specified',
() {
const chromeDinoState = SkillShotState(
const skillShotState = SkillShotState(
spriteState: SkillShotSpriteState.lit,
isBlinking: true,
);
expect(
chromeDinoState.copyWith(),
equals(chromeDinoState),
skillShotState.copyWith(),
equals(skillShotState),
);
},
);
@ -60,7 +60,7 @@ void main() {
'copies correctly '
'when all arguments specified',
() {
const chromeDinoState = SkillShotState(
const skillShotState = SkillShotState(
spriteState: SkillShotSpriteState.lit,
isBlinking: true,
);
@ -68,10 +68,10 @@ void main() {
spriteState: SkillShotSpriteState.dimmed,
isBlinking: false,
);
expect(chromeDinoState, isNot(equals(otherSkillShotState)));
expect(skillShotState, isNot(equals(otherSkillShotState)));
expect(
chromeDinoState.copyWith(
skillShotState.copyWith(
spriteState: SkillShotSpriteState.dimmed,
isBlinking: false,
),

@ -62,7 +62,7 @@ void main() {
group('loads', () {
flameTester.test(
'an AndroidSpaceship',
'an AndroidSpaceship',
(game) async {
await game.pump(AndroidAcres());
expect(

@ -0,0 +1,120 @@
// ignore_for_file: cascade_invocations
import 'dart:async';
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/components/google_gallery/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.googleWord.letter1.lit.keyName,
Assets.images.googleWord.letter1.dimmed.keyName,
Assets.images.googleWord.letter2.lit.keyName,
Assets.images.googleWord.letter2.dimmed.keyName,
Assets.images.googleWord.letter3.lit.keyName,
Assets.images.googleWord.letter3.dimmed.keyName,
Assets.images.googleWord.letter4.lit.keyName,
Assets.images.googleWord.letter4.dimmed.keyName,
Assets.images.googleWord.letter5.lit.keyName,
Assets.images.googleWord.letter5.dimmed.keyName,
Assets.images.googleWord.letter6.lit.keyName,
Assets.images.googleWord.letter6.dimmed.keyName,
]);
}
Future<void> pump(
GoogleGallery child, {
required GameBloc gameBloc,
required GoogleWordCubit googleWordBloc,
}) async {
// Not needed once https://github.com/flame-engine/flame/issues/1607
// is fixed
await onLoad();
await ensureAdd(
FlameMultiBlocProvider(
providers: [
FlameBlocProvider<GameBloc, GameState>.value(
value: gameBloc,
),
FlameBlocProvider<GoogleWordCubit, GoogleWordState>.value(
value: googleWordBloc,
),
],
children: [child],
),
);
}
}
class _MockGameBloc extends Mock implements GameBloc {}
class _MockGoogleWordCubit extends Mock implements GoogleWordCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('GoogleWordBonusBehavior', () {
late GameBloc gameBloc;
setUp(() {
gameBloc = _MockGameBloc();
});
final flameTester = FlameTester(_TestGame.new);
flameTester.testGameWidget(
'adds GameBonus.googleWord to the game when all letters '
'in google word are activated and calls onBonusAwarded',
setUp: (game, tester) async {
final behavior = GoogleWordBonusBehavior();
final parent = GoogleGallery.test();
final googleWord = GoogleWord(position: Vector2.zero());
final googleWordBloc = _MockGoogleWordCubit();
final streamController = StreamController<GoogleWordState>();
whenListen(
googleWordBloc,
streamController.stream,
initialState: GoogleWordState.initial(),
);
await parent.add(googleWord);
await game.pump(
parent,
gameBloc: gameBloc,
googleWordBloc: googleWordBloc,
);
await parent.ensureAdd(behavior);
streamController.add(
const GoogleWordState(
letterSpriteStates: {
0: GoogleLetterSpriteState.lit,
1: GoogleLetterSpriteState.lit,
2: GoogleLetterSpriteState.lit,
3: GoogleLetterSpriteState.lit,
4: GoogleLetterSpriteState.lit,
5: GoogleLetterSpriteState.lit,
},
),
);
await tester.pump();
verify(
() => gameBloc.add(const BonusActivated(GameBonus.googleWord)),
).called(1);
verify(googleWordBloc.onBonusAwarded).called(1);
},
);
});
}

@ -0,0 +1,110 @@
// ignore_for_file: cascade_invocations
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/google_gallery/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.googleWord.letter1.lit.keyName,
Assets.images.googleWord.letter1.dimmed.keyName,
Assets.images.googleWord.letter2.lit.keyName,
Assets.images.googleWord.letter2.dimmed.keyName,
Assets.images.googleWord.letter3.lit.keyName,
Assets.images.googleWord.letter3.dimmed.keyName,
Assets.images.googleWord.letter4.lit.keyName,
Assets.images.googleWord.letter4.dimmed.keyName,
Assets.images.googleWord.letter5.lit.keyName,
Assets.images.googleWord.letter5.dimmed.keyName,
Assets.images.googleWord.letter6.lit.keyName,
Assets.images.googleWord.letter6.dimmed.keyName,
Assets.images.googleRollover.left.decal.keyName,
Assets.images.googleRollover.left.pin.keyName,
Assets.images.googleRollover.right.decal.keyName,
Assets.images.googleRollover.right.pin.keyName,
]);
}
Future<void> pump(GoogleGallery child) async {
await ensureAdd(
FlameBlocProvider<GameBloc, GameState>.value(
value: _MockGameBloc(),
children: [child],
),
);
}
}
class _MockGameBloc extends Mock implements GameBloc {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group('GoogleGallery', () {
flameTester.test('loads correctly', (game) async {
final component = GoogleGallery();
await game.pump(component);
expect(game.descendants(), contains(component));
});
group('loads', () {
flameTester.test(
'two GoogleRollovers',
(game) async {
await game.pump(GoogleGallery());
expect(
game.descendants().whereType<GoogleRollover>().length,
equals(2),
);
},
);
flameTester.test(
'a GoogleWord',
(game) async {
await game.pump(GoogleGallery());
expect(
game.descendants().whereType<GoogleWord>().length,
equals(1),
);
},
);
});
group('adds', () {
flameTester.test(
'ScoringContactBehavior to GoogleRollovers',
(game) async {
await game.pump(GoogleGallery());
game.descendants().whereType<GoogleRollover>().forEach(
(rollover) => expect(
rollover.firstChild<ScoringContactBehavior>(),
isNotNull,
),
);
},
);
flameTester.test('a GoogleWordBonusBehavior', (game) async {
final component = GoogleGallery();
await game.pump(component);
expect(
component.descendants().whereType<GoogleWordBonusBehavior>().single,
isNotNull,
);
});
});
});
}

@ -1,94 +0,0 @@
// ignore_for_file: cascade_invocations
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/components/google_word/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.loadAll([
Assets.images.googleWord.letter1.lit.keyName,
Assets.images.googleWord.letter1.dimmed.keyName,
Assets.images.googleWord.letter2.lit.keyName,
Assets.images.googleWord.letter2.dimmed.keyName,
Assets.images.googleWord.letter3.lit.keyName,
Assets.images.googleWord.letter3.dimmed.keyName,
Assets.images.googleWord.letter4.lit.keyName,
Assets.images.googleWord.letter4.dimmed.keyName,
Assets.images.googleWord.letter5.lit.keyName,
Assets.images.googleWord.letter5.dimmed.keyName,
Assets.images.googleWord.letter6.lit.keyName,
Assets.images.googleWord.letter6.dimmed.keyName,
]);
}
Future<void> pump(GoogleWord child, {required GameBloc gameBloc}) async {
await ensureAdd(
FlameBlocProvider<GameBloc, GameState>.value(
value: gameBloc,
children: [
FlameProvider<PinballAudioPlayer>.value(
_MockPinballAudioPlayer(),
children: [child],
)
],
),
);
}
}
class _MockGameBloc extends Mock implements GameBloc {}
class _MockPinballAudioPlayer extends Mock implements PinballAudioPlayer {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('GoogleWordBonusBehaviors', () {
late GameBloc gameBloc;
setUp(() {
gameBloc = _MockGameBloc();
});
final flameTester = FlameTester(_TestGame.new);
flameTester.testGameWidget(
'adds GameBonus.googleWord to the game when all letters are activated',
setUp: (game, tester) async {
await game.onLoad();
final behavior = GoogleWordBonusBehavior();
final parent = GoogleWord.test();
final letters = [
GoogleLetter(0),
GoogleLetter(1),
GoogleLetter(2),
GoogleLetter(3),
GoogleLetter(4),
GoogleLetter(5),
];
await parent.addAll(letters);
await game.pump(parent, gameBloc: gameBloc);
await parent.ensureAdd(behavior);
for (final letter in letters) {
letter.bloc.onBallContacted();
}
await tester.pump();
verify(
() => gameBloc.add(const BonusActivated(GameBonus.googleWord)),
).called(1);
},
);
});
}

@ -184,11 +184,11 @@ void main() {
);
flameTester.test(
'one GoogleWord',
'one GoogleGallery',
(game) async {
await game.ready();
expect(
game.descendants().whereType<GoogleWord>().length,
game.descendants().whereType<GoogleGallery>().length,
equals(1),
);
},

@ -29,7 +29,7 @@ void main() {
expect(find.text('Play'), findsOneWidget);
});
testWidgets('adds PlayTapped event to StartGameBloc when taped',
testWidgets('adds PlayTapped event to StartGameBloc when tapped',
(tester) async {
await tester.pumpApp(
const PlayButtonOverlay(),

Loading…
Cancel
Save