fix: fixed merge conflicts at android acres

pull/416/head
RuiAlonso 3 years ago
commit f40c9aa327

@ -18,7 +18,7 @@ class AssetsManagerCubit extends Cubit<AssetsManagerState> {
/// delay here, which is a bit random in duration but enough to let the UI
/// do its job without adding too much delay for the user, we are letting
/// the UI paint first, and then we start loading the assets.
await Future<void>.delayed(const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(seconds: 1));
emit(
state.copyWith(
loadables: [

@ -5,4 +5,5 @@ export 'bumper_noise_behavior.dart';
export 'camera_focusing_behavior.dart';
export 'character_selection_behavior.dart';
export 'cow_bumper_noise_behavior.dart';
export 'kicker_noise_behavior.dart';
export 'scoring_behavior.dart';

@ -0,0 +1,11 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart';
class KickerNoiseBehavior extends ContactBehavior {
@override
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
readProvider<PinballAudioPlayer>().play(PinballAudio.kicker);
}
}

@ -16,6 +16,8 @@ class GameBloc extends Bloc<GameEvent, GameState> {
on<GameStarted>(_onGameStarted);
}
static const _maxScore = 9999999999;
void _onGameStarted(GameStarted _, Emitter emit) {
emit(state.copyWith(status: GameStatus.playing));
}
@ -25,7 +27,10 @@ class GameBloc extends Bloc<GameEvent, GameState> {
}
void _onRoundLost(RoundLost event, Emitter emit) {
final score = state.totalScore + state.roundScore * state.multiplier;
final score = math.min(
state.totalScore + state.roundScore * state.multiplier,
_maxScore,
);
final roundsLeft = math.max(state.rounds - 1, 0);
emit(
@ -41,9 +46,11 @@ class GameBloc extends Bloc<GameEvent, GameState> {
void _onScored(Scored event, Emitter emit) {
if (state.status.isPlaying) {
emit(
state.copyWith(roundScore: state.roundScore + event.points),
final combinedScore = math.min(
state.totalScore + state.roundScore + event.points,
_maxScore,
);
emit(state.copyWith(roundScore: combinedScore - state.totalScore));
}
}

@ -46,6 +46,7 @@ class AndroidAcres extends Component {
AndroidBumper.cow(
children: [
ScoringContactBehavior(points: Points.twentyThousand),
BumperNoiseBehavior(),
CowBumperNoiseBehavior(),
],
)..initialPosition = Vector2(-20.7, -13),

@ -1,4 +1,6 @@
// cSpell:ignore sublist
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flutter/material.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:pinball/l10n/l10n.dart';
@ -23,6 +25,23 @@ final _bodyTextPaint = TextPaint(
),
);
double _calcY(int i) => (i * 3.2) + 3.2;
const _columns = [-14.0, 0.0, 14.0];
String _rank(int number) {
switch (number) {
case 1:
return '${number}st';
case 2:
return '${number}nd';
case 3:
return '${number}rd';
default:
return '${number}th';
}
}
/// {@template leaderboard_display}
/// Component that builds the leaderboard list of the Backbox.
/// {@endtemplate}
@ -33,21 +52,47 @@ class LeaderboardDisplay extends PositionComponent with HasGameRef {
final List<LeaderboardEntryData> _entries;
double _calcY(int i) => (i * 3.2) + 3.2;
_MovePageArrow _findArrow({required bool active}) {
return descendants()
.whereType<_MovePageArrow>()
.firstWhere((arrow) => arrow.active == active);
}
static const _columns = [-15.0, 0.0, 15.0];
void _changePage(List<LeaderboardEntryData> ranking, int offset) {
final current = descendants().whereType<_RankingPage>().single;
final activeArrow = _findArrow(active: true);
final inactiveArrow = _findArrow(active: false);
String _rank(int number) {
switch (number) {
case 1:
return '${number}st';
case 2:
return '${number}nd';
case 3:
return '${number}rd';
default:
return '${number}th';
}
activeArrow.active = false;
current.add(
ScaleEffect.to(
Vector2(0, 1),
EffectController(
duration: 0.5,
curve: Curves.easeIn,
),
)..onFinishCallback = () {
current.removeFromParent();
inactiveArrow.active = true;
firstChild<PositionComponent>()?.add(
_RankingPage(
ranking: ranking,
offset: offset,
)
..scale = Vector2(0, 1)
..add(
ScaleEffect.to(
Vector2(1, 1),
EffectController(
duration: 0.5,
curve: Curves.easeIn,
),
),
),
);
},
);
}
@override
@ -60,6 +105,20 @@ class LeaderboardDisplay extends PositionComponent with HasGameRef {
PositionComponent(
position: Vector2(0, 4),
children: [
_MovePageArrow(
position: Vector2(20, 9),
onTap: () {
_changePage(_entries.sublist(5), 5);
},
),
_MovePageArrow(
position: Vector2(-20, 9),
direction: ArrowIconDirection.left,
active: false,
onTap: () {
_changePage(_entries.take(5).toList(), 0);
},
),
PositionComponent(
children: [
TextComponent(
@ -82,39 +141,106 @@ class LeaderboardDisplay extends PositionComponent with HasGameRef {
),
],
),
for (var i = 0; i < ranking.length; i++)
PositionComponent(
children: [
TextComponent(
text: _rank(i + 1),
textRenderer: _bodyTextPaint,
position: Vector2(_columns[0], _calcY(i)),
anchor: Anchor.center,
),
TextComponent(
text: ranking[i].score.formatScore(),
textRenderer: _bodyTextPaint,
position: Vector2(_columns[1], _calcY(i)),
anchor: Anchor.center,
),
SpriteComponent.fromImage(
gameRef.images.fromCache(
ranking[i].character.toTheme.leaderboardIcon.keyName,
),
anchor: Anchor.center,
size: Vector2(1.8, 1.8),
position: Vector2(_columns[2] - 2.5, _calcY(i) + .25),
),
TextComponent(
text: ranking[i].playerInitials,
textRenderer: _bodyTextPaint,
position: Vector2(_columns[2] + 1, _calcY(i)),
anchor: Anchor.center,
),
],
),
_RankingPage(
ranking: ranking,
offset: 0,
),
],
),
);
}
}
class _RankingPage extends PositionComponent with HasGameRef {
_RankingPage({
required this.ranking,
required this.offset,
}) : super(children: []);
final List<LeaderboardEntryData> ranking;
final int offset;
@override
Future<void> onLoad() async {
await addAll([
for (var i = 0; i < ranking.length; i++)
PositionComponent(
children: [
TextComponent(
text: _rank(i + 1 + offset),
textRenderer: _bodyTextPaint,
position: Vector2(_columns[0], _calcY(i)),
anchor: Anchor.center,
),
TextComponent(
text: ranking[i].score.formatScore(),
textRenderer: _bodyTextPaint,
position: Vector2(_columns[1], _calcY(i)),
anchor: Anchor.center,
),
SpriteComponent.fromImage(
gameRef.images.fromCache(
ranking[i].character.toTheme.leaderboardIcon.keyName,
),
anchor: Anchor.center,
size: Vector2(1.8, 1.8),
position: Vector2(_columns[2] - 3, _calcY(i) + .25),
),
TextComponent(
text: ranking[i].playerInitials,
textRenderer: _bodyTextPaint,
position: Vector2(_columns[2] + 1, _calcY(i)),
anchor: Anchor.center,
),
],
),
]);
}
}
class _MovePageArrow extends PositionComponent {
_MovePageArrow({
required Vector2 position,
required this.onTap,
this.direction = ArrowIconDirection.right,
bool active = true,
}) : super(
position: position,
children: [
if (active)
ArrowIcon(
position: Vector2.zero(),
direction: direction,
onTap: onTap,
),
SequenceEffect(
[
ScaleEffect.to(
Vector2.all(1.2),
EffectController(duration: 1),
),
ScaleEffect.to(Vector2.all(1), EffectController(duration: 1)),
],
infinite: true,
),
],
);
final ArrowIconDirection direction;
final VoidCallback onTap;
bool get active => children.whereType<ArrowIcon>().isNotEmpty;
set active(bool value) {
if (value) {
add(
ArrowIcon(
position: Vector2.zero(),
direction: direction,
onTap: onTap,
),
);
} else {
firstChild<ArrowIcon>()?.removeFromParent();
}
}
}

@ -52,6 +52,7 @@ class _BottomGroupSide extends Component {
children: [
ScoringContactBehavior(points: Points.fiveThousand)
..applyTo(['bouncy_edge']),
KickerNoiseBehavior()..applyTo(['bouncy_edge']),
],
)..initialPosition = Vector2(
(22.44 * direction) + centerXAdjustment,

@ -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),
@ -141,6 +145,8 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.skillShot.pin.keyName),
images.load(components.Assets.images.skillShot.lit.keyName),
images.load(components.Assets.images.skillShot.dimmed.keyName),
images.load(components.Assets.images.displayArrows.arrowLeft.keyName),
images.load(components.Assets.images.displayArrows.arrowRight.keyName),
images.load(androidTheme.leaderboardIcon.keyName),
images.load(androidTheme.background.keyName),
images.load(androidTheme.ball.keyName),

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

@ -23,6 +23,8 @@ class $AssetsSfxGen {
String get gameOverVoiceOver => 'assets/sfx/game_over_voice_over.mp3';
String get google => 'assets/sfx/google.mp3';
String get ioPinballVoiceOver => 'assets/sfx/io_pinball_voice_over.mp3';
String get kickerA => 'assets/sfx/kicker_a.mp3';
String get kickerB => 'assets/sfx/kicker_b.mp3';
String get launcher => 'assets/sfx/launcher.mp3';
String get sparky => 'assets/sfx/sparky.mp3';
}

@ -30,6 +30,9 @@ enum PinballAudio {
/// Launcher.
launcher,
/// Kicker.
kicker,
/// Sparky.
sparky,
@ -113,39 +116,67 @@ class _LoopAudio extends _Audio {
}
}
class _BumperAudio extends _Audio {
_BumperAudio({
class _SingleLoopAudio extends _LoopAudio {
_SingleLoopAudio({
required PreCacheSingleAudio preCacheSingleAudio,
required LoopSingleAudio loopSingleAudio,
required String path,
}) : super(
preCacheSingleAudio: preCacheSingleAudio,
loopSingleAudio: loopSingleAudio,
path: path,
);
bool _playing = false;
@override
void play() {
if (!_playing) {
super.play();
_playing = true;
}
}
}
class _RandomABAudio extends _Audio {
_RandomABAudio({
required this.createAudioPool,
required this.seed,
required this.audioAssetA,
required this.audioAssetB,
this.volume,
});
final CreateAudioPool createAudioPool;
final Random seed;
final String audioAssetA;
final String audioAssetB;
final double? volume;
late AudioPool bumperA;
late AudioPool bumperB;
late AudioPool audioA;
late AudioPool audioB;
@override
Future<void> load() async {
await Future.wait(
[
createAudioPool(
prefixFile(Assets.sfx.bumperA),
prefixFile(audioAssetA),
maxPlayers: 4,
prefix: '',
).then((pool) => bumperA = pool),
).then((pool) => audioA = pool),
createAudioPool(
prefixFile(Assets.sfx.bumperB),
prefixFile(audioAssetB),
maxPlayers: 4,
prefix: '',
).then((pool) => bumperB = pool),
).then((pool) => audioB = pool),
],
);
}
@override
void play() {
(seed.nextBool() ? bumperA : bumperB).start(volume: 0.6);
(seed.nextBool() ? audioA : audioB).start(volume: volume ?? 1);
}
}
@ -241,9 +272,19 @@ class PinballAudioPlayer {
playSingleAudio: _playSingleAudio,
path: Assets.sfx.gameOverVoiceOver,
),
PinballAudio.bumper: _BumperAudio(
PinballAudio.bumper: _RandomABAudio(
createAudioPool: _createAudioPool,
seed: _seed,
audioAssetA: Assets.sfx.bumperA,
audioAssetB: Assets.sfx.bumperB,
volume: 0.6,
),
PinballAudio.kicker: _RandomABAudio(
createAudioPool: _createAudioPool,
seed: _seed,
audioAssetA: Assets.sfx.kickerA,
audioAssetB: Assets.sfx.kickerB,
volume: 0.6,
),
PinballAudio.cowMoo: _ThrottledAudio(
preCacheSingleAudio: _preCacheSingleAudio,
@ -251,7 +292,7 @@ class PinballAudioPlayer {
path: Assets.sfx.cowMoo,
duration: const Duration(seconds: 2),
),
PinballAudio.backgroundMusic: _LoopAudio(
PinballAudio.backgroundMusic: _SingleLoopAudio(
preCacheSingleAudio: _preCacheSingleAudio,
loopSingleAudio: _loopSingleAudio,
path: Assets.music.background,

@ -119,6 +119,26 @@ void main() {
).called(1);
});
test('creates the kicker pools', () async {
await Future.wait(audioPlayer.load());
verify(
() => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerA}',
maxPlayers: 4,
prefix: '',
),
).called(1);
verify(
() => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerB}',
maxPlayers: 4,
prefix: '',
),
).called(1);
});
test('configures the audio cache instance', () async {
await Future.wait(audioPlayer.load());
@ -234,6 +254,55 @@ void main() {
});
});
group('kicker', () {
late AudioPool kickerAPool;
late AudioPool kickerBPool;
setUp(() {
kickerAPool = _MockAudioPool();
when(() => kickerAPool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {});
when(
() => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerA}',
maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
),
).thenAnswer((_) async => kickerAPool);
kickerBPool = _MockAudioPool();
when(() => kickerBPool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {});
when(
() => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerB}',
maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
),
).thenAnswer((_) async => kickerBPool);
});
group('when seed is true', () {
test('plays the kicker A sound pool', () async {
when(seed.nextBool).thenReturn(true);
await Future.wait(audioPlayer.load());
audioPlayer.play(PinballAudio.kicker);
verify(() => kickerAPool.start(volume: 0.6)).called(1);
});
});
group('when seed is false', () {
test('plays the kicker B sound pool', () async {
when(seed.nextBool).thenReturn(false);
await Future.wait(audioPlayer.load());
audioPlayer.play(PinballAudio.kicker);
verify(() => kickerBPool.start(volume: 0.6)).called(1);
});
});
});
group('cow moo', () {
test('plays the correct file', () async {
await Future.wait(audioPlayer.load());
@ -378,6 +447,18 @@ void main() {
.onCall('packages/pinball_audio/${Assets.music.background}'),
).called(1);
});
test('plays only once', () async {
await Future.wait(audioPlayer.load());
audioPlayer
..play(PinballAudio.backgroundMusic)
..play(PinballAudio.backgroundMusic);
verify(
() => loopSingleAudio
.onCall('packages/pinball_audio/${Assets.music.background}'),
).called(1);
});
});
test(

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 KiB

After

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 968 B

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -23,12 +23,17 @@ class $AssetsImagesGen {
$AssetsImagesDashGen get dash => const $AssetsImagesDashGen();
$AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen();
$AssetsImagesDisplayArrowsGen get displayArrows =>
const $AssetsImagesDisplayArrowsGen();
/// File path: assets/images/error_background.png
AssetGenImage get errorBackground =>
const AssetGenImage('assets/images/error_background.png');
$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();
@ -140,6 +145,15 @@ class $AssetsImagesDinoGen {
const AssetGenImage('assets/images/dino/top_wall_tunnel.png');
}
class $AssetsImagesDisplayArrowsGen {
const $AssetsImagesDisplayArrowsGen();
AssetGenImage get arrowLeft =>
const AssetGenImage('assets/images/display_arrows/arrow_left.png');
AssetGenImage get arrowRight =>
const AssetGenImage('assets/images/display_arrows/arrow_right.png');
}
class $AssetsImagesFlapperGen {
const $AssetsImagesFlapperGen();
@ -168,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();
@ -422,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();

@ -0,0 +1,49 @@
import 'package:flame/components.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
/// enum with the available directions for an [ArrowIcon].
enum ArrowIconDirection {
/// Left.
left,
/// Right.
right,
}
/// {@template arrow_icon}
/// A [SpriteComponent] that renders a simple arrow icon.
/// {@endtemplate}
class ArrowIcon extends SpriteComponent with Tappable, HasGameRef {
/// {@macro arrow_icon}
ArrowIcon({
required Vector2 position,
required this.direction,
required this.onTap,
}) : super(position: position);
final ArrowIconDirection direction;
final VoidCallback onTap;
@override
Future<void> onLoad() async {
anchor = Anchor.center;
final sprite = Sprite(
gameRef.images.fromCache(
direction == ArrowIconDirection.left
? Assets.images.displayArrows.arrowLeft.keyName
: Assets.images.displayArrows.arrowRight.keyName,
),
);
size = sprite.originalSize / 20;
this.sprite = sprite;
}
@override
bool onTapUp(TapUpInfo info) {
onTap();
return true;
}
}

@ -2,6 +2,7 @@ export 'android_animatronic.dart';
export 'android_bumper/android_bumper.dart';
export 'android_spaceship/android_spaceship.dart';
export 'arcade_background/arcade_background.dart';
export 'arrow_icon.dart';
export 'ball/ball.dart';
export 'baseboard.dart';
export 'board_background_sprite_component.dart';
@ -16,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/
@ -93,6 +95,7 @@ flutter:
- assets/images/backbox/button/
- assets/images/flapper/
- assets/images/skill_shot/
- assets/images/display_arrows/
flutter_gen:
line_length: 80

@ -21,6 +21,7 @@ void main() {
addScoreStories(dashbook);
addMultiballStories(dashbook);
addMultipliersStories(dashbook);
addArrowIconStories(dashbook);
runApp(dashbook);
}

@ -0,0 +1,37 @@
import 'package:flame/game.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/games.dart';
class ArrowIconGame extends AssetsGame with HasTappables {
ArrowIconGame()
: super(
imagesFileNames: [
Assets.images.displayArrows.arrowLeft.keyName,
Assets.images.displayArrows.arrowRight.keyName,
],
);
static const description = 'Shows how ArrowIcons are rendered.';
@override
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
await add(
ArrowIcon(
position: Vector2.zero(),
direction: ArrowIconDirection.left,
onTap: () {},
),
);
await add(
ArrowIcon(
position: Vector2(0, 20),
direction: ArrowIconDirection.right,
onTap: () {},
),
);
}
}

@ -0,0 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/arrow_icon/arrow_icon_game.dart';
void addArrowIconStories(Dashbook dashbook) {
dashbook.storiesOf('ArrowIcon').addGame(
title: 'Basic',
description: ArrowIconGame.description,
gameBuilder: (context) => ArrowIconGame(),
);
}

@ -1,4 +1,5 @@
export 'android_acres/stories.dart';
export 'arrow_icon/stories.dart';
export 'ball/stories.dart';
export 'bottom_group/stories.dart';
export 'boundaries/stories.dart';

@ -1,3 +1,4 @@
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
@ -20,3 +21,7 @@ class TestGame extends Forge2DGame {
class KeyboardTestGame extends TestGame with HasKeyboardHandlerComponents {
KeyboardTestGame([List<String>? assets]) : super(assets);
}
class TappablesTestGame extends TestGame with HasTappables {
TappablesTestGame([List<String>? assets]) : super(assets);
}

@ -0,0 +1,96 @@
// ignore_for_file: cascade_invocations, one_member_abstracts
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 '../../helpers/helpers.dart';
abstract class _VoidCallbackStubBase {
void onCall();
}
class _VoidCallbackStub extends Mock implements _VoidCallbackStubBase {}
void main() {
group('ArrowIcon', () {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.displayArrows.arrowLeft.keyName,
Assets.images.displayArrows.arrowRight.keyName,
];
final flameTester = FlameTester(() => TappablesTestGame(assets));
flameTester.testGameWidget(
'is tappable',
setUp: (game, tester) async {
final stub = _VoidCallbackStub();
await game.images.loadAll(assets);
await game.ensureAdd(
ArrowIcon(
position: Vector2.zero(),
direction: ArrowIconDirection.left,
onTap: stub.onCall,
),
);
await tester.pump();
await tester.tapAt(Offset.zero);
await tester.pump();
},
verify: (game, tester) async {
final icon = game.descendants().whereType<ArrowIcon>().single;
verify(icon.onTap).called(1);
},
);
group('left', () {
flameTester.testGameWidget(
'renders correctly',
setUp: (game, tester) async {
await game.images.loadAll(assets);
game.camera.followVector2(Vector2.zero());
await game.add(
ArrowIcon(
position: Vector2.zero(),
direction: ArrowIconDirection.left,
onTap: () {},
),
);
await tester.pump();
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/arrow_icon_left.png'),
);
},
);
});
group('right', () {
flameTester.testGameWidget(
'renders correctly',
setUp: (game, tester) async {
await game.images.loadAll(assets);
game.camera.followVector2(Vector2.zero());
await game.add(
ArrowIcon(
position: Vector2.zero(),
direction: ArrowIconDirection.right,
onTap: () {},
),
);
await tester.pump();
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/arrow_icon_right.png'),
);
},
);
});
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 915 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 850 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save