From 0a52583519629e4c7b73db90e6e2a069b67f1d90 Mon Sep 17 00:00:00 2001 From: arturplaczek <33895544+arturplaczek@users.noreply.github.com> Date: Wed, 4 May 2022 18:44:24 +0200 Subject: [PATCH 1/2] fix: mock flame images (#332) --- .../view/widgets/bonus_animation_test.dart | 14 +-- test/game/view/widgets/game_hud_test.dart | 15 +-- .../widgets/play_button_overlay_test.dart | 10 +- test/helpers/fakes.dart | 67 -------------- test/helpers/helpers.dart | 1 + test/helpers/mock_flame_images.dart | 92 +++++++++++++++++++ .../view/character_selection_page_test.dart | 8 +- 7 files changed, 101 insertions(+), 106 deletions(-) create mode 100644 test/helpers/mock_flame_images.dart diff --git a/test/game/view/widgets/bonus_animation_test.dart b/test/game/view/widgets/bonus_animation_test.dart index 2284ca8d..52c1b3d8 100644 --- a/test/game/view/widgets/bonus_animation_test.dart +++ b/test/game/view/widgets/bonus_animation_test.dart @@ -1,9 +1,5 @@ // ignore_for_file: invalid_use_of_protected_member -import 'dart:typed_data'; - -import 'package:flame/assets.dart'; -import 'package:flame/flame.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -13,8 +9,6 @@ import 'package:pinball_flame/pinball_flame.dart'; import '../../../helpers/helpers.dart'; -class _MockImages extends Mock implements Images {} - class _MockCallback extends Mock { void call(); } @@ -24,13 +18,7 @@ void main() { const animationDuration = 6; setUp(() async { - // TODO(arturplaczek): need to find for a better solution for loading image - // or use original images from BonusAnimation.loadAssets() - final image = await decodeImageFromList(Uint8List.fromList(fakeImage)); - final images = _MockImages(); - when(() => images.fromCache(any())).thenReturn(image); - when(() => images.load(any())).thenAnswer((_) => Future.value(image)); - Flame.images = images; + await mockFlameImages(); }); group('loads SpriteAnimationWidget correctly for', () { diff --git a/test/game/view/widgets/game_hud_test.dart b/test/game/view/widgets/game_hud_test.dart index f8be70c2..75fa7439 100644 --- a/test/game/view/widgets/game_hud_test.dart +++ b/test/game/view/widgets/game_hud_test.dart @@ -1,11 +1,8 @@ // ignore_for_file: prefer_const_constructors import 'dart:async'; -import 'dart:typed_data'; import 'package:bloc_test/bloc_test.dart'; -import 'package:flame/assets.dart'; -import 'package:flame/flame.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -18,8 +15,6 @@ import 'package:pinball_ui/pinball_ui.dart'; import '../../../helpers/helpers.dart'; -class _MockImages extends Mock implements Images {} - class _MockGameBloc extends Mock implements GameBloc {} void main() { @@ -34,15 +29,9 @@ void main() { ); setUp(() async { - gameBloc = _MockGameBloc(); + await mockFlameImages(); - // TODO(arturplaczek): need to find for a better solution for loading - // image or use original images from BonusAnimation.loadAssets() - final image = await decodeImageFromList(Uint8List.fromList(fakeImage)); - final images = _MockImages(); - when(() => images.fromCache(any())).thenReturn(image); - when(() => images.load(any())).thenAnswer((_) => Future.value(image)); - Flame.images = images; + gameBloc = _MockGameBloc(); whenListen( gameBloc, diff --git a/test/game/view/widgets/play_button_overlay_test.dart b/test/game/view/widgets/play_button_overlay_test.dart index 1d7070e0..843592c3 100644 --- a/test/game/view/widgets/play_button_overlay_test.dart +++ b/test/game/view/widgets/play_button_overlay_test.dart @@ -1,10 +1,8 @@ import 'package:bloc_test/bloc_test.dart'; -import 'package:flame/flame.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/select_character/select_character.dart'; -import 'package:pinball_theme/pinball_theme.dart'; import '../../../helpers/helpers.dart'; @@ -21,14 +19,12 @@ void main() { late CharacterThemeCubit characterThemeCubit; setUp(() async { - Flame.images.prefix = ''; - await Flame.images.load(const DashTheme().animation.keyName); - await Flame.images.load(const AndroidTheme().animation.keyName); - await Flame.images.load(const DinoTheme().animation.keyName); - await Flame.images.load(const SparkyTheme().animation.keyName); + await mockFlameImages(); + game = _MockPinballGame(); gameFlowController = _MockGameFlowController(); characterThemeCubit = _MockCharacterThemeCubit(); + whenListen( characterThemeCubit, const Stream.empty(), diff --git a/test/helpers/fakes.dart b/test/helpers/fakes.dart index d782ede4..706733a1 100644 --- a/test/helpers/fakes.dart +++ b/test/helpers/fakes.dart @@ -5,70 +5,3 @@ import 'package:pinball/game/game.dart'; class FakeContact extends Fake implements Contact {} class FakeGameEvent extends Fake implements GameEvent {} - -const fakeImage = [ - 0x89, - 0x50, - 0x4E, - 0x47, - 0x0D, - 0x0A, - 0x1A, - 0x0A, - 0x00, - 0x00, - 0x00, - 0x0D, - 0x49, - 0x48, - 0x44, - 0x52, - 0x00, - 0x00, - 0x00, - 0x01, - 0x00, - 0x00, - 0x00, - 0x01, - 0x08, - 0x06, - 0x00, - 0x00, - 0x00, - 0x1F, - 0x15, - 0xC4, - 0x89, - 0x00, - 0x00, - 0x00, - 0x0A, - 0x49, - 0x44, - 0x41, - 0x54, - 0x78, - 0x9C, - 0x63, - 0x00, - 0x01, - 0x00, - 0x00, - 0x05, - 0x00, - 0x01, - 0x0D, - 0x0A, - 0x2D, - 0xB4, - 0x00, - 0x00, - 0x00, - 0x00, - 0x49, - 0x45, - 0x4E, - 0x44, - 0xAE, -]; diff --git a/test/helpers/helpers.dart b/test/helpers/helpers.dart index febf8d36..6621abcc 100644 --- a/test/helpers/helpers.dart +++ b/test/helpers/helpers.dart @@ -2,6 +2,7 @@ export 'builders.dart'; export 'fakes.dart'; export 'forge2d.dart'; export 'key_testers.dart'; +export 'mock_flame_images.dart'; export 'pump_app.dart'; export 'test_games.dart'; export 'text_span.dart'; diff --git a/test/helpers/mock_flame_images.dart b/test/helpers/mock_flame_images.dart new file mode 100644 index 00000000..48e4d40e --- /dev/null +++ b/test/helpers/mock_flame_images.dart @@ -0,0 +1,92 @@ +import 'dart:typed_data'; + +import 'package:flame/assets.dart'; +import 'package:flame/flame.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class _MockImages extends Mock implements Images {} + +/// {@template mock_flame_images} +/// Mock for flame images instance. +/// +/// Using real images blocks the tests, for this reason we need fake image +/// everywhere we use [Images.fromCache] or [Images.load]. +/// {@endtemplate} +// TODO(arturplaczek): need to find for a better solution for loading image +// or use original images. +Future mockFlameImages() async { + final image = await decodeImageFromList(Uint8List.fromList(_fakeImage)); + final images = _MockImages(); + when(() => images.fromCache(any())).thenReturn(image); + when(() => images.load(any())).thenAnswer((_) => Future.value(image)); + Flame.images = images; +} + +const _fakeImage = [ + 0x89, + 0x50, + 0x4E, + 0x47, + 0x0D, + 0x0A, + 0x1A, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x0D, + 0x49, + 0x48, + 0x44, + 0x52, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x01, + 0x08, + 0x06, + 0x00, + 0x00, + 0x00, + 0x1F, + 0x15, + 0xC4, + 0x89, + 0x00, + 0x00, + 0x00, + 0x0A, + 0x49, + 0x44, + 0x41, + 0x54, + 0x78, + 0x9C, + 0x63, + 0x00, + 0x01, + 0x00, + 0x00, + 0x05, + 0x00, + 0x01, + 0x0D, + 0x0A, + 0x2D, + 0xB4, + 0x00, + 0x00, + 0x00, + 0x00, + 0x49, + 0x45, + 0x4E, + 0x44, + 0xAE, +]; diff --git a/test/select_character/view/character_selection_page_test.dart b/test/select_character/view/character_selection_page_test.dart index 28033030..7d64dd39 100644 --- a/test/select_character/view/character_selection_page_test.dart +++ b/test/select_character/view/character_selection_page_test.dart @@ -1,5 +1,4 @@ import 'package:bloc_test/bloc_test.dart'; -import 'package:flame/flame.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -17,11 +16,8 @@ void main() { late CharacterThemeCubit characterThemeCubit; setUp(() async { - Flame.images.prefix = ''; - await Flame.images.load(const DashTheme().animation.keyName); - await Flame.images.load(const AndroidTheme().animation.keyName); - await Flame.images.load(const DinoTheme().animation.keyName); - await Flame.images.load(const SparkyTheme().animation.keyName); + await mockFlameImages(); + characterThemeCubit = _MockCharacterThemeCubit(); whenListen( characterThemeCubit, From 94206bddaadec477fc8f9dd291dce6af72bb55c8 Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Wed, 4 May 2022 18:54:08 +0200 Subject: [PATCH 2/2] fix: both `Fipper`s should respond to multi touch taps (#330) * fix: both flippers should respond to multi touch taps * fix: both flippers should respond to multi touch taps Co-authored-by: Tom Arra --- lib/game/pinball_game.dart | 19 +++++++------- test/game/pinball_game_test.dart | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index d49216fb..aa963a53 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -81,7 +81,7 @@ class PinballGame extends PinballForge2DGame await super.onLoad(); } - BoardSide? focusedBoardSide; + final focusedBoardSide = {}; @override void onTapDown(int pointerId, TapDownInfo info) { @@ -94,9 +94,10 @@ class PinballGame extends PinballForge2DGame descendants().whereType().single.pullFor(2); } else { final leftSide = info.eventPosition.widget.x < canvasSize.x / 2; - focusedBoardSide = leftSide ? BoardSide.left : BoardSide.right; + focusedBoardSide[pointerId] = + leftSide ? BoardSide.left : BoardSide.right; final flippers = descendants().whereType().where((flipper) { - return flipper.side == focusedBoardSide; + return flipper.side == focusedBoardSide[pointerId]; }); flippers.first.moveUp(); } @@ -107,23 +108,23 @@ class PinballGame extends PinballForge2DGame @override void onTapUp(int pointerId, TapUpInfo info) { - _moveFlippersDown(); + _moveFlippersDown(pointerId); super.onTapUp(pointerId, info); } @override void onTapCancel(int pointerId) { - _moveFlippersDown(); + _moveFlippersDown(pointerId); super.onTapCancel(pointerId); } - void _moveFlippersDown() { - if (focusedBoardSide != null) { + void _moveFlippersDown(int pointerId) { + if (focusedBoardSide[pointerId] != null) { final flippers = descendants().whereType().where((flipper) { - return flipper.side == focusedBoardSide; + return flipper.side == focusedBoardSide[pointerId]; }); flippers.first.moveDown(); - focusedBoardSide = null; + focusedBoardSide.remove(pointerId); } } } diff --git a/test/game/pinball_game_test.dart b/test/game/pinball_game_test.dart index 99817454..ca31f280 100644 --- a/test/game/pinball_game_test.dart +++ b/test/game/pinball_game_test.dart @@ -415,6 +415,51 @@ void main() { expect(flippers.first.body.linearVelocity.y, isPositive); }); + + flameTester.test( + 'multiple touches control both flippers', + (game) async { + await game.ready(); + + final raw = _MockTapDownDetails(); + when(() => raw.kind).thenReturn(PointerDeviceKind.touch); + + final leftEventPosition = _MockEventPosition(); + when(() => leftEventPosition.game).thenReturn(Vector2.zero()); + when(() => leftEventPosition.widget).thenReturn(Vector2.zero()); + + final rightEventPosition = _MockEventPosition(); + when(() => rightEventPosition.game).thenReturn(Vector2.zero()); + when(() => rightEventPosition.widget).thenReturn(game.canvasSize); + + final leftTapDownEvent = _MockTapDownInfo(); + when(() => leftTapDownEvent.eventPosition) + .thenReturn(leftEventPosition); + when(() => leftTapDownEvent.raw).thenReturn(raw); + + final rightTapDownEvent = _MockTapDownInfo(); + when(() => rightTapDownEvent.eventPosition) + .thenReturn(rightEventPosition); + when(() => rightTapDownEvent.raw).thenReturn(raw); + + final flippers = game.descendants().whereType(); + final rightFlipper = flippers.elementAt(0); + final leftFlipper = flippers.elementAt(1); + + game.onTapDown(0, leftTapDownEvent); + game.onTapDown(1, rightTapDownEvent); + + expect(leftFlipper.body.linearVelocity.y, isNegative); + expect(leftFlipper.side, equals(BoardSide.left)); + expect(rightFlipper.body.linearVelocity.y, isNegative); + expect(rightFlipper.side, equals(BoardSide.right)); + + expect( + game.focusedBoardSide, + equals({0: BoardSide.left, 1: BoardSide.right}), + ); + }, + ); }); group('plunger control', () {