feat: google letter animation sequence (#431)

Co-authored-by: Tom Arra <tarra3@gmail.com>
pull/437/head
Allison Ryan 2 years ago committed by GitHub
parent 326265c640
commit 1e804694ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,6 +19,7 @@ class GoogleWordBonusBehavior extends Component {
.add(const BonusActivated(GameBonus.googleWord));
readBloc<GoogleWordCubit, GoogleWordState>().onBonusAwarded();
add(BonusBallSpawningBehavior());
add(GoogleWordAnimatingBehavior());
},
),
);

@ -0,0 +1,24 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball_components/pinball_components.dart';
class GoogleWordAnimatingBehavior extends TimerComponent
with FlameBlocReader<GoogleWordCubit, GoogleWordState> {
GoogleWordAnimatingBehavior() : super(period: 0.35, repeat: true);
final _maxBlinks = 7;
int _blinks = 0;
@override
void onTick() {
super.onTick();
if (_blinks != _maxBlinks * 2) {
bloc.switched();
_blinks++;
} else {
timer.stop();
bloc.onAnimationFinished();
shouldRemove = true;
}
}
}

@ -23,7 +23,52 @@ class GoogleWordCubit extends Cubit<GoogleWordState> {
}
}
void switched() {
switch (state.letterSpriteStates[0]!) {
case GoogleLetterSpriteState.lit:
emit(
GoogleWordState(
letterSpriteStates: {
for (int i = 0; i < _lettersInGoogle; i++)
if (i.isEven)
i: GoogleLetterSpriteState.dimmed
else
i: GoogleLetterSpriteState.lit
},
),
);
break;
case GoogleLetterSpriteState.dimmed:
emit(
GoogleWordState(
letterSpriteStates: {
for (int i = 0; i < _lettersInGoogle; i++)
if (i.isEven)
i: GoogleLetterSpriteState.lit
else
i: GoogleLetterSpriteState.dimmed
},
),
);
break;
}
}
void onBonusAwarded() {
emit(
GoogleWordState(
letterSpriteStates: {
for (int i = 0; i < _lettersInGoogle; i++)
if (i.isEven)
i: GoogleLetterSpriteState.lit
else
i: GoogleLetterSpriteState.dimmed
},
),
);
}
void onAnimationFinished() {
emit(GoogleWordState.initial());
_lastLitLetter = 0;
}

@ -1,6 +1,7 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
export 'behaviors/behaviors.dart';
export 'cubit/google_word_cubit.dart';
/// {@template google_word}

@ -0,0 +1,64 @@
// 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_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
Future<void> pump(
GoogleWordAnimatingBehavior child, {
required GoogleWordCubit bloc,
}) async {
await ensureAdd(
FlameBlocProvider<GoogleWordCubit, GoogleWordState>.value(
value: bloc,
children: [child],
),
);
}
}
class _MockGoogleWordCubit extends Mock implements GoogleWordCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group('GoogleWordAnimatingBehavior', () {
flameTester.testGameWidget(
'calls switched after timer period reached',
setUp: (game, tester) async {
final behavior = GoogleWordAnimatingBehavior();
final bloc = _MockGoogleWordCubit();
await game.pump(behavior, bloc: bloc);
game.update(behavior.timer.limit);
verify(bloc.switched).called(1);
},
);
flameTester.testGameWidget(
'calls onAnimationFinished and removes itself '
'after all blinks complete',
setUp: (game, tester) async {
final behavior = GoogleWordAnimatingBehavior();
final bloc = _MockGoogleWordCubit();
await game.pump(behavior, bloc: bloc);
for (var i = 0; i <= 14; i++) {
game.update(behavior.timer.limit);
}
await game.ready();
verify(bloc.onAnimationFinished).called(1);
expect(
game.descendants().whereType<GoogleWordAnimatingBehavior>().isEmpty,
isTrue,
);
},
);
});
}

@ -6,6 +6,21 @@ void main() {
group(
'GoogleWordCubit',
() {
final litEvens = {
for (int i = 0; i < 6; i++)
if (i.isEven)
i: GoogleLetterSpriteState.lit
else
i: GoogleLetterSpriteState.dimmed
};
final litOdds = {
for (int i = 0; i < 6; i++)
if (i.isOdd)
i: GoogleLetterSpriteState.lit
else
i: GoogleLetterSpriteState.dimmed
};
blocTest<GoogleWordCubit, GoogleWordState>(
'onRolloverContacted emits first letter lit',
build: GoogleWordCubit.new,
@ -25,9 +40,31 @@ void main() {
);
blocTest<GoogleWordCubit, GoogleWordState>(
'onBonusAwarded emits initial state',
'switched emits all even letters lit when first letter is dimmed',
build: GoogleWordCubit.new,
act: (bloc) => bloc.switched(),
expect: () => [GoogleWordState(letterSpriteStates: litEvens)],
);
blocTest<GoogleWordCubit, GoogleWordState>(
'switched emits all odd letters lit when first letter is lit',
build: GoogleWordCubit.new,
seed: () => GoogleWordState(letterSpriteStates: litEvens),
act: (bloc) => bloc.switched(),
expect: () => [GoogleWordState(letterSpriteStates: litOdds)],
);
blocTest<GoogleWordCubit, GoogleWordState>(
'onBonusAwarded emits all even letters lit',
build: GoogleWordCubit.new,
act: (bloc) => bloc.onBonusAwarded(),
expect: () => [GoogleWordState(letterSpriteStates: litEvens)],
);
blocTest<GoogleWordCubit, GoogleWordState>(
'onAnimationFinished emits initial state',
build: GoogleWordCubit.new,
act: (bloc) => bloc.onAnimationFinished(),
expect: () => [GoogleWordState.initial()],
);
},

@ -119,8 +119,8 @@ void main() {
);
flameTester.testGameWidget(
'adds BonusBallSpawningBehavior to the game when all letters '
'in google word are activated',
'adds BonusBallSpawningBehavior and GoogleWordAnimatingBehavior '
'to the game when all letters in google word are activated',
setUp: (game, tester) async {
final behavior = GoogleWordBonusBehavior();
final parent = GoogleGallery.test();
@ -161,6 +161,10 @@ void main() {
game.descendants().whereType<BonusBallSpawningBehavior>().length,
equals(1),
);
expect(
game.descendants().whereType<GoogleWordAnimatingBehavior>().length,
equals(1),
);
},
);
});

Loading…
Cancel
Save