mirror of https://github.com/flutter/pinball.git
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
parent
ea33c1c889
commit
48c5c80b38
@ -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();
|
||||
}
|
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 83 KiB |
After Width: | Height: | Size: 2.2 KiB |
@ -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 +0,0 @@
|
||||
export 'google_letter_ball_contact_behavior.dart';
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export 'google_rollover_ball_contact_behavior.dart';
|
@ -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),
|
||||
],
|
||||
);
|
||||
}
|
@ -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));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -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);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Reference in new issue