Merge branch 'main' into update-checkout

pull/499/head
Álvaro Stivi 1 year ago committed by GitHub
commit 9742ff3dd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,5 +0,0 @@
{
"projects": {
"default": "pinball-dev"
}
}

@ -1,3 +0,0 @@
# Every request must be reviewed and accepted by:
* @erickzanardo @alestiago @RuiMiguel @allisonryan0002

@ -11,7 +11,7 @@ jobs:
uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1
with: with:
flutter_channel: stable flutter_channel: stable
flutter_version: 2.10.5 flutter_version: 3.22.2
coverage_excludes: "lib/gen/*.dart" coverage_excludes: "lib/gen/*.dart"
test_optimization: false test_optimization: false

6
.gitignore vendored

@ -100,12 +100,14 @@ unlinked_spec.ds
# Coverage # Coverage
coverage/ coverage/
# Golden tests related
**/failures
# Submodules # Submodules
!pubspec.lock !pubspec.lock
packages/**/pubspec.lock packages/**/pubspec.lock
# Web related # Web related
lib/generated_plugin_registrant.dart
# Symbolication related # Symbolication related
app.*.symbols app.*.symbols
@ -128,6 +130,8 @@ app.*.map.json
# Firebase related # Firebase related
.firebase .firebase
firebase.json
lib/firebase_options.dart
test/.test_runner.dart test/.test_runner.dart
web/__/firebase/init.js web/__/firebase/init.js

@ -15,6 +15,7 @@
"dpad", "dpad",
"endtemplate", "endtemplate",
"firestore", "firestore",
"flutterfire",
"gapless", "gapless",
"genhtml", "genhtml",
"goldens", "goldens",
@ -22,6 +23,7 @@
"leaderboard", "leaderboard",
"loadables", "loadables",
"localizable", "localizable",
"macos",
"mixins", "mixins",
"mocktail", "mocktail",
"mostrado", "mostrado",
@ -47,4 +49,4 @@
"ignorePaths": [ "ignorePaths": [
".github/workflows/**" ".github/workflows/**"
] ]
} }

@ -19,6 +19,17 @@ _Created using [Very Good CLI][very_good_cli_link] 🤖_
## Getting Started 🚀 ## Getting Started 🚀
### Firebase
First, please create a Firebase project for development.
After you create your project, remember to activate the following features:
- **Authentication** with the **anonymous** option
- **Firestore** with the rules in firestore.rules.
Next, use the instructions on [Firebase website](https://firebase.google.com/docs/flutter/setup?platform=web) to set up the **flutterfire_cli**.
Allow it to override the **lib/firebase_options.dart** file with your project settings.
### Running locally
To run the desired project either use the launch configuration in VSCode/Android Studio or use the following commands: To run the desired project either use the launch configuration in VSCode/Android Studio or use the following commands:
```sh ```sh

@ -0,0 +1,4 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
- flame: true

@ -1,33 +0,0 @@
{
"firestore": {
"rules": "firestore.rules"
},
"hosting": {
"public": "build/web",
"site": "",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"headers": [
{
"source": "**/*.@(jpg|jpeg|gif|png)",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=3600"
}
]
},
{
"source": "**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
}
]
},
"storage": {
"rules": "storage.rules"
}
}

@ -19,6 +19,7 @@ class AssetsManagerCubit extends Cubit<AssetsManagerState> {
/// do its job without adding too much delay for the user, we are letting /// 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. /// the UI paint first, and then we start loading the assets.
await Future<void>.delayed(const Duration(seconds: 1)); await Future<void>.delayed(const Duration(seconds: 1));
if (isClosed) return;
final loadables = <Future<void> Function()>[ final loadables = <Future<void> Function()>[
_game.preFetchLeaderboard, _game.preFetchLeaderboard,
..._game.preLoadAssets(), ..._game.preLoadAssets(),

@ -16,7 +16,7 @@ class AssetsLoadingPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = context.l10n; final l10n = context.l10n;
final headline1 = Theme.of(context).textTheme.headline1; final displayLarge = Theme.of(context).textTheme.displayLarge;
return Container( return Container(
decoration: const CrtBackground(), decoration: const CrtBackground(),
child: Center( child: Center(
@ -30,7 +30,7 @@ class AssetsLoadingPage extends StatelessWidget {
const SizedBox(height: 40), const SizedBox(height: 40),
AnimatedEllipsisText( AnimatedEllipsisText(
l10n.loading, l10n.loading,
style: headline1, style: displayLarge,
), ),
const SizedBox(height: 40), const SizedBox(height: 40),
FractionallySizedBox( FractionallySizedBox(

@ -1,10 +1,6 @@
import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/widgets.dart';
class AppBlocObserver extends BlocObserver { class AppBlocObserver extends BlocObserver {
@override @override
@ -19,30 +15,3 @@ class AppBlocObserver extends BlocObserver {
super.onError(bloc, error, stackTrace); super.onError(bloc, error, stackTrace);
} }
} }
typedef BootstrapBuilder = Future<Widget> Function(
FirebaseFirestore firestore,
FirebaseAuth firebaseAuth,
);
Future<void> bootstrap(BootstrapBuilder builder) async {
WidgetsFlutterBinding.ensureInitialized();
FlutterError.onError = (details) {
log(details.exceptionAsString(), stackTrace: details.stack);
};
await runZonedGuarded(
() async {
await BlocOverrides.runZoned(
() async => runApp(
await builder(
FirebaseFirestore.instance,
FirebaseAuth.instance,
),
),
blocObserver: AppBlocObserver(),
);
},
(error, stackTrace) => log(error.toString(), stackTrace: stackTrace),
);
}

@ -0,0 +1,63 @@
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for android - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.iOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for ios - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: '',
appId: '',
messagingSenderId: '',
projectId: '',
authDomain: '',
storageBucket: '',
);
}

@ -1,5 +1,4 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class AnimatronicLoopingBehavior extends TimerComponent class AnimatronicLoopingBehavior extends TimerComponent
with ParentIsA<SpriteAnimationComponent> { with ParentIsA<SpriteAnimationComponent> {
@ -10,8 +9,8 @@ class AnimatronicLoopingBehavior extends TimerComponent
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
parent.animation?.onComplete = () { parent.animationTicker?.onComplete = () {
parent.animation?.reset(); parent.animationTicker?.reset();
parent.playing = false; parent.playing = false;
timer timer
..reset() ..reset()

@ -1,11 +1,10 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template focus_data} /// {@template focus_data}
/// Defines a [Camera] focus point. /// Defines a [CameraComponent] focus point.
/// {@endtemplate} /// {@endtemplate}
class _FocusData { class _FocusData {
/// {@macro focus_data} /// {@macro focus_data}
@ -69,16 +68,14 @@ class CameraFocusingBehavior extends Component
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
onGameResize(gameRef.camera.viewport.size);
_snap(GameStatus.waiting); _snap(GameStatus.waiting);
} }
void _snap(GameStatus focusKey) { void _snap(GameStatus focusKey) {
final focusData = _foci[_activeFocus = focusKey]!; final focusData = _foci[_activeFocus = focusKey]!;
gameRef.camera.moveTo(focusData.position, speed: 100);
gameRef.camera gameRef.camera.viewfinder.zoom = focusData.zoom;
..speed = 100
..followVector2(focusData.position)
..zoom = focusData.zoom;
} }
void _zoomTo(GameStatus focusKey) { void _zoomTo(GameStatus focusKey) {

@ -53,7 +53,11 @@ class Backbox extends PositionComponent with ZIndex, HasGameRef {
_build(_bloc.state); _build(_bloc.state);
_subscription = _bloc.stream.listen((state) { _subscription = _bloc.stream.listen((state) {
_display.children.removeWhere((_) => true); final removals = _display.children.map((child) {
_display.remove(child);
return child.removed;
});
Future.wait(removals);
_build(state); _build(state);
}); });
} }

@ -2,7 +2,7 @@ part of 'backbox_bloc.dart';
/// {@template backbox_state} /// {@template backbox_state}
/// The base state for all [BackboxState]. /// The base state for all [BackboxState].
/// {@endtemplate backbox_state} /// {@endtemplate}
abstract class BackboxState extends Equatable { abstract class BackboxState extends Equatable {
/// {@macro backbox_state} /// {@macro backbox_state}
const BackboxState(); const BackboxState();

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/input.dart'; import 'package:flame/events.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/l10n/l10n.dart';
@ -164,7 +164,7 @@ class _LinksComponent extends PositionComponent with HasGameRef {
/// {@template share_link_component} /// {@template share_link_component}
/// Link button to navigate to sharing score display. /// Link button to navigate to sharing score display.
/// {@endtemplate} /// {@endtemplate}
class ShareLinkComponent extends TextComponent with HasGameRef, Tappable { class ShareLinkComponent extends TextComponent with HasGameRef, TapCallbacks {
/// {@macro share_link_component} /// {@macro share_link_component}
ShareLinkComponent({ ShareLinkComponent({
OnShareTap? onTap, OnShareTap? onTap,
@ -178,7 +178,7 @@ class ShareLinkComponent extends TextComponent with HasGameRef, Tappable {
final OnShareTap? _onTap; final OnShareTap? _onTap;
@override @override
bool onTapDown(TapDownInfo info) { bool onTapDown(TapDownEvent event) {
_onTap?.call(); _onTap?.call();
return true; return true;
} }
@ -202,7 +202,8 @@ class ShareLinkComponent extends TextComponent with HasGameRef, Tappable {
/// {@template google_io_link_component} /// {@template google_io_link_component}
/// Link button to navigate to Google I/O site. /// Link button to navigate to Google I/O site.
/// {@endtemplate} /// {@endtemplate}
class GoogleIOLinkComponent extends TextComponent with HasGameRef, Tappable { class GoogleIOLinkComponent extends TextComponent
with HasGameRef, TapCallbacks {
/// {@macro google_io_link_component} /// {@macro google_io_link_component}
GoogleIOLinkComponent() GoogleIOLinkComponent()
: super( : super(
@ -212,7 +213,7 @@ class GoogleIOLinkComponent extends TextComponent with HasGameRef, Tappable {
); );
@override @override
bool onTapUp(TapUpInfo info) { bool onTapUp(TapUpEvent event) {
openLink(ShareRepository.googleIOEvent); openLink(ShareRepository.googleIOEvent);
return true; return true;
} }
@ -280,7 +281,8 @@ class _FirebaseTextComponent extends TextComponent with HasGameRef {
/// Link text to navigate to Open Source site. /// Link text to navigate to Open Source site.
/// {@endtemplate} /// {@endtemplate}
@visibleForTesting @visibleForTesting
class OpenSourceTextComponent extends TextComponent with HasGameRef, Tappable { class OpenSourceTextComponent extends TextComponent
with HasGameRef, TapCallbacks {
/// {@macro open_source_link_component} /// {@macro open_source_link_component}
OpenSourceTextComponent() OpenSourceTextComponent()
: super( : super(
@ -290,7 +292,7 @@ class OpenSourceTextComponent extends TextComponent with HasGameRef, Tappable {
); );
@override @override
bool onTapUp(TapUpInfo info) { bool onTapUp(TapUpEvent event) {
openLink(ShareRepository.openSourceCode); openLink(ShareRepository.openSourceCode);
return true; return true;
} }

@ -72,7 +72,7 @@ class LeaderboardDisplay extends PositionComponent with HasGameRef {
duration: 0.5, duration: 0.5,
curve: Curves.easeIn, curve: Curves.easeIn,
), ),
)..onFinishCallback = () { )..onComplete = () {
current.removeFromParent(); current.removeFromParent();
inactiveArrow.active = true; inactiveArrow.active = true;
firstChild<PositionComponent>()?.add( firstChild<PositionComponent>()?.add(

@ -18,6 +18,7 @@ final _bodyTextPaint = TextPaint(
/// {@endtemplate} /// {@endtemplate}
class LoadingDisplay extends TextComponent { class LoadingDisplay extends TextComponent {
/// {@template loading_display} /// {@template loading_display}
/// {@endtemplate}
LoadingDisplay(); LoadingDisplay();
late final String _label; late final String _label;

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/input.dart'; import 'package:flame/events.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
@ -127,7 +127,7 @@ class _SocialNetworksComponent extends PositionComponent with HasGameRef {
/// Button for sharing on Facebook. /// Button for sharing on Facebook.
/// {@endtemplate} /// {@endtemplate}
class FacebookButtonComponent extends SpriteComponent class FacebookButtonComponent extends SpriteComponent
with HasGameRef, Tappable { with HasGameRef, TapCallbacks {
/// {@macro facebook_button_component} /// {@macro facebook_button_component}
FacebookButtonComponent({ FacebookButtonComponent({
OnSocialShareTap? onTap, OnSocialShareTap? onTap,
@ -140,7 +140,7 @@ class FacebookButtonComponent extends SpriteComponent
final OnSocialShareTap? _onTap; final OnSocialShareTap? _onTap;
@override @override
bool onTapUp(TapUpInfo info) { bool onTapUp(TapUpEvent event) {
_onTap?.call(SharePlatform.facebook); _onTap?.call(SharePlatform.facebook);
return true; return true;
} }
@ -159,7 +159,8 @@ class FacebookButtonComponent extends SpriteComponent
/// {@template twitter_button_component} /// {@template twitter_button_component}
/// Button for sharing on Twitter. /// Button for sharing on Twitter.
/// {@endtemplate} /// {@endtemplate}
class TwitterButtonComponent extends SpriteComponent with HasGameRef, Tappable { class TwitterButtonComponent extends SpriteComponent
with HasGameRef, TapCallbacks {
/// {@macro twitter_button_component} /// {@macro twitter_button_component}
TwitterButtonComponent({ TwitterButtonComponent({
OnSocialShareTap? onTap, OnSocialShareTap? onTap,
@ -172,7 +173,7 @@ class TwitterButtonComponent extends SpriteComponent with HasGameRef, Tappable {
final OnSocialShareTap? _onTap; final OnSocialShareTap? _onTap;
@override @override
bool onTapUp(TapUpInfo info) { bool onTapUp(TapUpEvent event) {
_onTap?.call(SharePlatform.twitter); _onTap?.call(SharePlatform.twitter);
return true; return true;
} }

@ -2,7 +2,6 @@ import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Adds a [GameBonus.dinoChomp] when a [Ball] is chomped by the [ChromeDino]. /// Adds a [GameBonus.dinoChomp] when a [Ball] is chomped by the [ChromeDino].
class ChromeDinoBonusBehavior extends Component class ChromeDinoBonusBehavior extends Component

@ -80,21 +80,18 @@ class GameBlocStatusListener extends Component
[ [
PlungerPullingBehavior(strength: 7), PlungerPullingBehavior(strength: 7),
PlungerAutoPullingBehavior(), PlungerAutoPullingBehavior(),
PlungerKeyControllingBehavior() PlungerKeyControllingBehavior(),
], ],
); );
void _removePlungerBehaviors(Plunger plunger) { void _removePlungerBehaviors(Plunger plunger) {
plunger plunger.children
.descendants()
.whereType<PlungerPullingBehavior>() .whereType<PlungerPullingBehavior>()
.forEach(plunger.remove); .forEach(plunger.remove);
plunger plunger.children
.descendants()
.whereType<PlungerAutoPullingBehavior>() .whereType<PlungerAutoPullingBehavior>()
.forEach(plunger.remove); .forEach(plunger.remove);
plunger plunger.children
.descendants()
.whereType<PlungerKeyControllingBehavior>() .whereType<PlungerKeyControllingBehavior>()
.forEach(plunger.remove); .forEach(plunger.remove);
} }
@ -103,8 +100,7 @@ class GameBlocStatusListener extends Component
.firstChild<FlameBlocProvider<FlipperCubit, FlipperState>>()! .firstChild<FlameBlocProvider<FlipperCubit, FlipperState>>()!
.add(FlipperKeyControllingBehavior()); .add(FlipperKeyControllingBehavior());
void _removeFlipperBehaviors(Flipper flipper) => flipper void _removeFlipperBehaviors(Flipper flipper) => flipper.children
.descendants()
.whereType<FlipperKeyControllingBehavior>() .whereType<FlipperKeyControllingBehavior>()
.forEach(flipper.remove); .forEach(flipper.remove);
} }

@ -2,7 +2,6 @@ import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Toggle each [Multiball] when there is a bonus ball. /// Toggle each [Multiball] when there is a bonus ball.
class MultiballsBehavior extends Component class MultiballsBehavior extends Component

@ -2,7 +2,6 @@ import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Toggle each [Multiplier] when GameState.multiplier changes. /// Toggle each [Multiplier] when GameState.multiplier changes.
class MultipliersBehavior extends Component class MultipliersBehavior extends Component

@ -2,7 +2,6 @@ import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Adds a [GameBonus.sparkyTurboCharge] when a [Ball] enters the /// Adds a [GameBonus.sparkyTurboCharge] when a [Ball] enters the
/// [SparkyComputer]. /// [SparkyComputer].

@ -1,9 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/game.dart'; import 'package:flame/events.dart';
import 'package:flame/input.dart'; import 'package:flame/input.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart';
@ -17,8 +18,8 @@ import 'package:pinball_flame/pinball_flame.dart';
import 'package:platform_helper/platform_helper.dart'; import 'package:platform_helper/platform_helper.dart';
import 'package:share_repository/share_repository.dart'; import 'package:share_repository/share_repository.dart';
class PinballGame extends PinballForge2DGame class PinballGame extends Forge2DGame
with HasKeyboardHandlerComponents, MultiTouchTapDetector, HasTappables { with HasKeyboardHandlerComponents, MultiTouchTapDetector {
PinballGame({ PinballGame({
required CharacterThemeCubit characterThemeBloc, required CharacterThemeCubit characterThemeBloc,
required this.leaderboardRepository, required this.leaderboardRepository,
@ -32,9 +33,7 @@ class PinballGame extends PinballForge2DGame
_audioPlayer = audioPlayer, _audioPlayer = audioPlayer,
_characterThemeBloc = characterThemeBloc, _characterThemeBloc = characterThemeBloc,
_l10n = l10n, _l10n = l10n,
super( super(gravity: Vector2(0, 30)) {
gravity: Vector2(0, 30),
) {
images.prefix = ''; images.prefix = '';
} }
@ -80,7 +79,7 @@ class PinballGame extends PinballForge2DGame
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await add( await world.add(
FlameMultiBlocProvider( FlameMultiBlocProvider(
providers: [ providers: [
FlameBlocProvider<GameBloc, GameState>.value( FlameBlocProvider<GameBloc, GameState>.value(
@ -147,7 +146,6 @@ class PinballGame extends PinballForge2DGame
], ],
), ),
); );
await super.onLoad(); await super.onLoad();
} }
@ -160,7 +158,8 @@ class PinballGame extends PinballForge2DGame
final rocket = descendants().whereType<RocketSpriteComponent>().first; final rocket = descendants().whereType<RocketSpriteComponent>().first;
final bounds = rocket.topLeftPosition & rocket.size; final bounds = rocket.topLeftPosition & rocket.size;
final tappedRocket = bounds.contains(info.eventPosition.game.toOffset()); final tappedRocket =
bounds.contains(screenToWorld(info.eventPosition.widget).toOffset());
if (tappedRocket) { if (tappedRocket) {
descendants() descendants()
.whereType<FlameBlocProvider<PlungerCubit, PlungerState>>() .whereType<FlameBlocProvider<PlungerCubit, PlungerState>>()
@ -213,7 +212,7 @@ class PinballGame extends PinballForge2DGame
} }
} }
class DebugPinballGame extends PinballGame with FPSCounter, PanDetector { class DebugPinballGame extends PinballGame with PanDetector {
DebugPinballGame({ DebugPinballGame({
required CharacterThemeCubit characterThemeBloc, required CharacterThemeCubit characterThemeBloc,
required LeaderboardRepository leaderboardRepository, required LeaderboardRepository leaderboardRepository,
@ -239,6 +238,7 @@ class DebugPinballGame extends PinballGame with FPSCounter, PanDetector {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
await addAll([PreviewLine(), _DebugInformation()]); await addAll([PreviewLine(), _DebugInformation()]);
camera.viewfinder.zoom = 50;
} }
@override @override
@ -247,16 +247,21 @@ class DebugPinballGame extends PinballGame with FPSCounter, PanDetector {
if (info.raw.kind == PointerDeviceKind.mouse) { if (info.raw.kind == PointerDeviceKind.mouse) {
final canvas = descendants().whereType<ZCanvasComponent>().single; final canvas = descendants().whereType<ZCanvasComponent>().single;
final ball = Ball()..initialPosition = info.eventPosition.game; final ball = Ball()
..initialPosition = screenToWorld(info.eventPosition.widget)
..zIndex = ZIndexes.ballOnBoard;
canvas.add(ball); canvas.add(ball);
world.add(ball);
} }
} }
@override @override
void onPanStart(DragStartInfo info) => lineStart = info.eventPosition.game; void onPanStart(DragStartInfo info) =>
lineStart = screenToWorld(info.eventPosition.widget);
@override @override
void onPanUpdate(DragUpdateInfo info) => lineEnd = info.eventPosition.game; void onPanUpdate(DragUpdateInfo info) =>
lineEnd = screenToWorld(info.eventPosition.widget);
@override @override
void onPanEnd(DragEndInfo info) { void onPanEnd(DragEndInfo info) {
@ -274,6 +279,8 @@ class DebugPinballGame extends PinballGame with FPSCounter, PanDetector {
final impulse = line * -1 * 10; final impulse = line * -1 * 10;
ball.add(BallTurboChargingBehavior(impulse: impulse)); ball.add(BallTurboChargingBehavior(impulse: impulse));
canvas.add(ball); canvas.add(ball);
add(ball);
world.add(ball);
} }
} }
@ -299,9 +306,6 @@ class PreviewLine extends PositionComponent with HasGameRef<DebugPinballGame> {
} }
class _DebugInformation extends Component with HasGameRef<DebugPinballGame> { class _DebugInformation extends Component with HasGameRef<DebugPinballGame> {
@override
PositionType get positionType => PositionType.widget;
final _debugTextPaint = TextPaint( final _debugTextPaint = TextPaint(
style: const TextStyle( style: const TextStyle(
color: Colors.green, color: Colors.green,
@ -314,14 +318,14 @@ class _DebugInformation extends Component with HasGameRef<DebugPinballGame> {
@override @override
void render(Canvas canvas) { void render(Canvas canvas) {
final debugText = [ final debugText = [
'FPS: ${gameRef.fps().toStringAsFixed(1)}', // 'FPS: ${gameRef.fps().toStringAsFixed(1)}',
'BALLS: ${gameRef.descendants().whereType<Ball>().length}', 'BALLS: ${gameRef.descendants().whereType<Ball>().length}',
].join(' | '); ].join(' | ');
final height = _debugTextPaint.measureTextHeight(debugText); final height = _debugTextPaint.getLineMetrics(debugText).height;
final position = Vector2(0, gameRef.camera.canvasSize.y - height); final position = Vector2(0, gameRef.camera.viewport.size.y - height);
canvas.drawRect( canvas.drawRect(
position & Vector2(gameRef.camera.canvasSize.x, height), position & Vector2(gameRef.camera.viewport.size.x, height),
_debugBackgroundPaint, _debugBackgroundPaint,
); );
_debugTextPaint.render(canvas, debugText, position); _debugTextPaint.render(canvas, debugText, position);

@ -118,7 +118,7 @@ class PinballGameLoadedView extends StatelessWidget {
right: 0, right: 0,
left: 0, left: 0,
child: ReplayButtonOverlay(), child: ReplayButtonOverlay(),
) ),
}, },
), ),
), ),

@ -93,6 +93,7 @@ class _BonusAnimationState extends State<BonusAnimation>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late SpriteAnimationController controller; late SpriteAnimationController controller;
late SpriteAnimation animation; late SpriteAnimation animation;
late SpriteAnimationTicker animationTicker;
bool shouldRunBuildCallback = true; bool shouldRunBuildCallback = true;
@override @override
@ -110,7 +111,7 @@ class _BonusAnimationState extends State<BonusAnimation>
shouldRunBuildCallback = oldWidget._imagePath == widget._imagePath; shouldRunBuildCallback = oldWidget._imagePath == widget._imagePath;
Future<void>.delayed( Future<void>.delayed(
Duration(seconds: animation.totalDuration().ceil()), Duration(seconds: duration()),
() { () {
widget._onCompleted?.call(); widget._onCompleted?.call();
}, },
@ -119,6 +120,10 @@ class _BonusAnimationState extends State<BonusAnimation>
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
} }
int duration() {
return animationTicker.totalDuration().ceil();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final spriteSheet = SpriteSheet.fromColumnsAndRows( final spriteSheet = SpriteSheet.fromColumnsAndRows(
@ -132,9 +137,10 @@ class _BonusAnimationState extends State<BonusAnimation>
to: spriteSheet.rows * spriteSheet.columns, to: spriteSheet.rows * spriteSheet.columns,
loop: false, loop: false,
); );
animationTicker = animation.createTicker();
Future<void>.delayed( Future<void>.delayed(
Duration(seconds: animation.totalDuration().ceil()), Duration(seconds: duration()),
() { () {
if (shouldRunBuildCallback) { if (shouldRunBuildCallback) {
widget._onCompleted?.call(); widget._onCompleted?.call();
@ -144,6 +150,7 @@ class _BonusAnimationState extends State<BonusAnimation>
controller = SpriteAnimationController( controller = SpriteAnimationController(
animation: animation, animation: animation,
animationTicker: animationTicker,
vsync: this, vsync: this,
)..forward(); )..forward();

@ -22,7 +22,7 @@ class _GameHudState extends State<GameHud> {
bool showAnimation = false; bool showAnimation = false;
/// Ratio from sprite frame (width 500, height 144) w / h = ratio /// Ratio from sprite frame (width 500, height 144) w / h = ratio
static const _ratio = 3.47; static const _ratio = 3.47222222222;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -34,7 +34,7 @@ class _GameHudState extends State<GameHud> {
return _ScoreViewDecoration( return _ScoreViewDecoration(
child: SizedBox( child: SizedBox(
height: height, height: height,
width: height * _ratio, width: (height * _ratio) + 16,
child: BlocListener<GameBloc, GameState>( child: BlocListener<GameBloc, GameState>(
listenWhen: (previous, current) => listenWhen: (previous, current) =>
previous.bonusHistory.length != current.bonusHistory.length, previous.bonusHistory.length != current.bonusHistory.length,

@ -6,6 +6,7 @@ import 'package:pinball_ui/pinball_ui.dart';
/// {@endtemplate} /// {@endtemplate}
class MobileDpad extends StatelessWidget { class MobileDpad extends StatelessWidget {
/// {@template mobile_dpad} /// {@template mobile_dpad}
/// {@endtemplate}
const MobileDpad({ const MobileDpad({
Key? key, Key? key,
required this.onTapUp, required this.onTapUp,

@ -20,7 +20,7 @@ class RoundCountDisplay extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.rounds, l10n.rounds,
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.displayLarge,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
Row( Row(

@ -39,7 +39,7 @@ class _GameOver extends StatelessWidget {
return Text( return Text(
l10n.gameOver, l10n.gameOver,
style: Theme.of(context).textTheme.headline1, style: Theme.of(context).textTheme.displayLarge,
); );
} }
} }
@ -60,7 +60,7 @@ class _ScoreDisplay extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.score.toLowerCase(), l10n.score.toLowerCase(),
style: Theme.of(context).textTheme.subtitle1, style: Theme.of(context).textTheme.titleMedium,
), ),
const _ScoreText(), const _ScoreText(),
const RoundCountDisplay(), const RoundCountDisplay(),
@ -81,7 +81,7 @@ class _ScoreText extends StatelessWidget {
return Text( return Text(
score.formatScore(), score.formatScore(),
style: Theme.of(context).textTheme.headline1, style: Theme.of(context).textTheme.displayLarge,
); );
} }
} }

@ -85,13 +85,12 @@ class _HowToPlayDialogState extends State<HowToPlayDialog> {
final isMobile = context.read<PlatformHelper>().isMobile; final isMobile = context.read<PlatformHelper>().isMobile;
final l10n = context.l10n; final l10n = context.l10n;
return WillPopScope( return PopScope(
onWillPop: () { onPopInvoked: (_) {
widget.onDismissCallback.call(); widget.onDismissCallback.call();
context context
.read<PinballAudioPlayer>() .read<PinballAudioPlayer>()
.play(PinballAudio.ioPinballVoiceOver); .play(PinballAudio.ioPinballVoiceOver);
return Future.value(true);
}, },
child: PinballDialog( child: PinballDialog(
title: l10n.howToPlay, title: l10n.howToPlay,
@ -132,20 +131,20 @@ class _MobileLaunchControls extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = context.l10n; final l10n = context.l10n;
final headline3 = Theme.of(context) final displaySmall = Theme.of(context)
.textTheme .textTheme
.headline3! .displaySmall!
.copyWith(color: PinballColors.white); .copyWith(color: PinballColors.white);
return Column( return Column(
children: [ children: [
Text(l10n.tapAndHoldRocket, style: headline3), Text(l10n.tapAndHoldRocket, style: displaySmall),
Text.rich( Text.rich(
TextSpan( TextSpan(
children: [ children: [
TextSpan(text: '${l10n.to} ', style: headline3), TextSpan(text: '${l10n.to} ', style: displaySmall),
TextSpan( TextSpan(
text: l10n.launch, text: l10n.launch,
style: headline3.copyWith(color: PinballColors.blue), style: displaySmall.copyWith(color: PinballColors.blue),
), ),
], ],
), ),
@ -163,7 +162,7 @@ class _MobileFlipperControls extends StatelessWidget {
final l10n = context.l10n; final l10n = context.l10n;
final headline3 = Theme.of(context) final headline3 = Theme.of(context)
.textTheme .textTheme
.headline3! .displaySmall!
.copyWith(color: PinballColors.white); .copyWith(color: PinballColors.white);
return Column( return Column(
children: [ children: [
@ -189,10 +188,10 @@ class _DesktopBody extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return const Padding(
padding: const EdgeInsets.all(16), padding: EdgeInsets.all(16),
child: Column( child: Column(
children: const [ children: [
_DesktopLaunchControls(), _DesktopLaunchControls(),
SizedBox(height: 16), SizedBox(height: 16),
_DesktopFlipperControls(), _DesktopFlipperControls(),
@ -212,18 +211,18 @@ class _DesktopLaunchControls extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.launchControls, l10n.launchControls,
style: Theme.of(context).textTheme.headline4, style: Theme.of(context).textTheme.headlineMedium,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Wrap( const Wrap(
children: const [ children: [
_KeyButton(control: Control.down), _KeyButton(control: Control.down),
SizedBox(width: 10), SizedBox(width: 10),
_KeyButton(control: Control.space), _KeyButton(control: Control.space),
SizedBox(width: 10), SizedBox(width: 10),
_KeyButton(control: Control.s), _KeyButton(control: Control.s),
], ],
) ),
], ],
); );
} }
@ -239,30 +238,30 @@ class _DesktopFlipperControls extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.flipperControls, l10n.flipperControls,
style: Theme.of(context).textTheme.headline4, style: Theme.of(context).textTheme.headlineMedium,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Column( const Column(
children: [ children: [
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: const [ children: [
_KeyButton(control: Control.left), _KeyButton(control: Control.left),
SizedBox(width: 20), SizedBox(width: 20),
_KeyButton(control: Control.right), _KeyButton(control: Control.right),
], ],
), ),
const SizedBox(height: 8), SizedBox(height: 8),
Wrap( Wrap(
children: const [ children: [
_KeyButton(control: Control.a), _KeyButton(control: Control.a),
SizedBox(width: 20), SizedBox(width: 20),
_KeyButton(control: Control.d), _KeyButton(control: Control.d),
], ],
) ),
], ],
) ),
], ],
); );
} }
@ -277,7 +276,7 @@ class _KeyButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme; final textTheme = Theme.of(context).textTheme;
final textStyle = final textStyle =
control.isArrow ? textTheme.headline1 : textTheme.headline3; control.isArrow ? textTheme.displayLarge : textTheme.displaySmall;
const height = 60.0; const height = 60.0;
final width = control.isSpace ? height * 2.83 : height; final width = control.isSpace ? height * 2.83 : height;
return DecoratedBox( return DecoratedBox(

@ -1,28 +1,41 @@
import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart'; import 'package:authentication_repository/authentication_repository.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:pinball/app/app.dart'; import 'package:pinball/app/app.dart';
import 'package:pinball/bootstrap.dart'; import 'package:pinball/bootstrap.dart';
import 'package:pinball/firebase_options.dart';
import 'package:pinball_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
import 'package:platform_helper/platform_helper.dart'; import 'package:platform_helper/platform_helper.dart';
import 'package:share_repository/share_repository.dart'; import 'package:share_repository/share_repository.dart';
void main() { Future<App> bootstrap() async {
bootstrap((firestore, firebaseAuth) async { WidgetsFlutterBinding.ensureInitialized();
final leaderboardRepository = LeaderboardRepository(firestore); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
const shareRepository = final leaderboardRepository =
ShareRepository(appUrl: ShareRepository.pinballGameUrl); LeaderboardRepository(FirebaseFirestore.instance);
final authenticationRepository = AuthenticationRepository(firebaseAuth); const shareRepository =
final pinballAudioPlayer = PinballAudioPlayer(); ShareRepository(appUrl: ShareRepository.pinballGameUrl);
final platformHelper = PlatformHelper(); final authenticationRepository =
await Firebase.initializeApp(); AuthenticationRepository(FirebaseAuth.instance);
await authenticationRepository.authenticateAnonymously(); final pinballAudioPlayer = PinballAudioPlayer();
return App( final platformHelper = PlatformHelper();
authenticationRepository: authenticationRepository, await authenticationRepository.authenticateAnonymously();
leaderboardRepository: leaderboardRepository, return App(
shareRepository: shareRepository, authenticationRepository: authenticationRepository,
pinballAudioPlayer: pinballAudioPlayer, leaderboardRepository: leaderboardRepository,
platformHelper: platformHelper, shareRepository: shareRepository,
); pinballAudioPlayer: pinballAudioPlayer,
}); platformHelper: platformHelper,
);
}
void main() async {
Bloc.observer = AppBlocObserver();
runApp(await bootstrap());
} }

@ -10,7 +10,6 @@ Future<void> showMoreInformationDialog(BuildContext context) {
return showDialog<void>( return showDialog<void>(
context: context, context: context,
barrierColor: PinballColors.transparent, barrierColor: PinballColors.transparent,
barrierDismissible: true,
builder: (_) { builder: (_) {
return Center( return Center(
child: SizedBox( child: SizedBox(
@ -32,11 +31,11 @@ class MoreInformationDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return const Material(
color: PinballColors.transparent, color: PinballColors.transparent,
child: _LinkBoxDecoration( child: _LinkBoxDecoration(
child: Column( child: Column(
children: const [ children: [
SizedBox(height: 16), SizedBox(height: 16),
_LinkBoxHeader(), _LinkBoxHeader(),
Expanded( Expanded(
@ -59,7 +58,7 @@ class _LinkBoxHeader extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.linkBoxTitle, l10n.linkBoxTitle,
style: Theme.of(context).textTheme.headline3!.copyWith( style: Theme.of(context).textTheme.displaySmall!.copyWith(
color: PinballColors.blue, color: PinballColors.blue,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@ -77,9 +76,8 @@ class _LinkBoxHeader extends StatelessWidget {
class _LinkBoxDecoration extends StatelessWidget { class _LinkBoxDecoration extends StatelessWidget {
const _LinkBoxDecoration({ const _LinkBoxDecoration({
Key? key,
required this.child, required this.child,
}) : super(key: key); });
final Widget child; final Widget child;
@ -156,7 +154,7 @@ class _TextLink extends StatelessWidget {
onTap: () => openLink(link), onTap: () => openLink(link),
child: Text( child: Text(
text, text,
style: theme.textTheme.headline5!.copyWith( style: theme.textTheme.headlineSmall!.copyWith(
color: PinballColors.white, color: PinballColors.white,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -176,7 +174,8 @@ class _MadeWithFlutterAndFirebase extends StatelessWidget {
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
text: l10n.linkBoxMadeWithText, text: l10n.linkBoxMadeWithText,
style: theme.textTheme.headline5!.copyWith(color: PinballColors.white), style:
theme.textTheme.headlineSmall!.copyWith(color: PinballColors.white),
children: <TextSpan>[ children: <TextSpan>[
TextSpan( TextSpan(
text: l10n.linkBoxFlutterLinkText, text: l10n.linkBoxFlutterLinkText,
@ -191,7 +190,7 @@ class _MadeWithFlutterAndFirebase extends StatelessWidget {
text: l10n.linkBoxFirebaseLinkText, text: l10n.linkBoxFirebaseLinkText,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => openLink(_MoreInformationUrl.firebaseWebsite), ..onTap = () => openLink(_MoreInformationUrl.firebaseWebsite),
style: theme.textTheme.headline5!.copyWith( style: theme.textTheme.headlineSmall!.copyWith(
decoration: TextDecoration.underline, decoration: TextDecoration.underline,
), ),
), ),

@ -8,7 +8,7 @@ import 'package:pinball_ui/pinball_ui.dart';
/// {@template character_selection_dialog} /// {@template character_selection_dialog}
/// Dialog used to select the playing character of the game. /// Dialog used to select the playing character of the game.
/// {@endtemplate character_selection_dialog} /// {@endtemplate}
class CharacterSelectionDialog extends StatelessWidget { class CharacterSelectionDialog extends StatelessWidget {
/// {@macro character_selection_dialog} /// {@macro character_selection_dialog}
const CharacterSelectionDialog({Key? key}) : super(key: key); const CharacterSelectionDialog({Key? key}) : super(key: key);
@ -137,7 +137,7 @@ class _Character extends StatelessWidget {
onPressed: () => onPressed: () =>
context.read<CharacterThemeCubit>().characterSelected(character), context.read<CharacterThemeCubit>().characterSelected(character),
style: ButtonStyle( style: ButtonStyle(
overlayColor: MaterialStateProperty.all( overlayColor: WidgetStateProperty.all(
PinballColors.transparent, PinballColors.transparent,
), ),
), ),

@ -60,7 +60,7 @@ class _SelectedCharacterState extends State<SelectedCharacter>
children: [ children: [
Text( Text(
widget.currentCharacter.name, widget.currentCharacter.name,
style: Theme.of(context).textTheme.headline2, style: Theme.of(context).textTheme.displayMedium,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
@ -95,7 +95,11 @@ class _SelectedCharacterState extends State<SelectedCharacter>
to: spriteSheet.rows * spriteSheet.columns, to: spriteSheet.rows * spriteSheet.columns,
); );
if (_controller != null) _controller?.dispose(); if (_controller != null) _controller?.dispose();
_controller = SpriteAnimationController(vsync: this, animation: animation) _controller = SpriteAnimationController(
vsync: this,
animation: animation,
animationTicker: animation.createTicker(),
)
..forward() ..forward()
..repeat(); ..repeat();
} }

@ -4,15 +4,17 @@ version: 1.0.0+1
publish_to: none publish_to: none
environment: environment:
sdk: ">=2.16.0 <3.0.0" sdk: "^3.4.3"
dependencies: dependencies:
firebase_auth: ^3.3.16 firebase_auth: ^5.1.1
firebase_core: ^3.1.1
flutter: flutter:
sdk: flutter sdk: flutter
intl: ^0.19.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mocktail: ^0.2.0 mocktail: ^1.0.4
very_good_analysis: ^2.4.0 very_good_analysis: ^6.0.0

@ -4,12 +4,12 @@ version: 1.0.0+1
publish_to: none publish_to: none
environment: environment:
sdk: ">=2.16.0 <3.0.0" sdk: "^3.4.3"
dependencies: dependencies:
vector_math: ^2.1.1 vector_math: ^2.1.1
dev_dependencies: dev_dependencies:
mocktail: ^0.2.0 mocktail: ^1.0.3
test: ^1.19.2 test: ^1.19.2
very_good_analysis: ^2.4.0 very_good_analysis: ^6.0.0

@ -4,20 +4,20 @@ version: 1.0.0+1
publish_to: none publish_to: none
environment: environment:
sdk: ">=2.16.0 <3.0.0" sdk: "^3.4.3"
dependencies: dependencies:
cloud_firestore: ^3.1.10 cloud_firestore: ^5.0.2
equatable: ^2.0.3 equatable: ^2.0.3
flutter: flutter:
sdk: flutter sdk: flutter
json_annotation: ^4.4.0 json_annotation: ^4.4.0
dev_dependencies: dev_dependencies:
build_runner: ^2.1.8 build_runner: ^2.4.11
flutter_test: flutter_test:
sdk: flutter sdk: flutter
json_serializable: ^6.1.5 json_serializable: ^6.1.5
mocktail: ^0.2.0 mocktail: ^1.0.4
test: ^1.19.2 test: ^1.25.2
very_good_analysis: ^2.4.0 very_good_analysis: ^6.0.0

@ -75,7 +75,7 @@ void main() {
when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{ when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{
'character': 'dash', 'character': 'dash',
'playerInitials': 'user$score', 'playerInitials': 'user$score',
'score': score 'score': score,
}); });
return queryDocumentSnapshot; return queryDocumentSnapshot;
}).toList(); }).toList();
@ -162,7 +162,7 @@ void main() {
when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{ when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{
'character': 'dash', 'character': 'dash',
'playerInitials': 'AAA', 'playerInitials': 'AAA',
'score': score 'score': score,
}); });
when(() => queryDocumentSnapshot.id).thenReturn('id$score'); when(() => queryDocumentSnapshot.id).thenReturn('id$score');
return queryDocumentSnapshot; return queryDocumentSnapshot;
@ -222,14 +222,14 @@ void main() {
6500, 6500,
6000, 6000,
5500, 5500,
5000 5000,
]; ];
final queryDocumentSnapshots = leaderboardScores.map((score) { final queryDocumentSnapshots = leaderboardScores.map((score) {
final queryDocumentSnapshot = _MockQueryDocumentSnapshot(); final queryDocumentSnapshot = _MockQueryDocumentSnapshot();
when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{ when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{
'character': 'dash', 'character': 'dash',
'playerInitials': 'AAA', 'playerInitials': 'AAA',
'score': score 'score': score,
}); });
when(() => queryDocumentSnapshot.id).thenReturn('id$score'); when(() => queryDocumentSnapshot.id).thenReturn('id$score');
return queryDocumentSnapshot; return queryDocumentSnapshot;
@ -269,7 +269,7 @@ void main() {
when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{ when(queryDocumentSnapshot.data).thenReturn(<String, dynamic>{
'character': 'dash', 'character': 'dash',
'playerInitials': 'AAA', 'playerInitials': 'AAA',
'score': score 'score': score,
}); });
when(() => queryDocumentSnapshot.id).thenReturn('id$score'); when(() => queryDocumentSnapshot.id).thenReturn('id$score');
when(() => queryDocumentSnapshot.reference) when(() => queryDocumentSnapshot.reference)

@ -1,8 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:audioplayers/audioplayers.dart';
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:flame_audio/audio_pool.dart';
import 'package:flame_audio/flame_audio.dart'; import 'package:flame_audio/flame_audio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball_audio/gen/assets.gen.dart'; import 'package:pinball_audio/gen/assets.gen.dart';
@ -53,12 +51,11 @@ enum PinballAudio {
} }
/// Defines the contract of the creation of an [AudioPool]. /// Defines the contract of the creation of an [AudioPool].
typedef CreateAudioPool = Future<AudioPool> Function( typedef CreateAudioPool = Future<AudioPool> Function({
String sound, { required Source source,
bool? repeating, required int maxPlayers,
int? maxPlayers, AudioCache? audioCache,
int? minPlayers, int minPlayers,
String? prefix,
}); });
/// Defines the contract for playing a single audio. /// Defines the contract for playing a single audio.
@ -165,9 +162,8 @@ class _SingleAudioPool extends _Audio {
@override @override
Future<void> load() async { Future<void> load() async {
pool = await createAudioPool( pool = await createAudioPool(
prefixFile(path), source: DeviceFileSource(prefixFile(path), mimeType: 'audio/mpeg'),
maxPlayers: maxPlayers, maxPlayers: maxPlayers,
prefix: '',
); );
} }
@ -198,14 +194,14 @@ class _RandomABAudio extends _Audio {
await Future.wait( await Future.wait(
[ [
createAudioPool( createAudioPool(
prefixFile(audioAssetA), source:
DeviceFileSource(prefixFile(audioAssetA), mimeType: 'audio/mpeg'),
maxPlayers: 4, maxPlayers: 4,
prefix: '',
).then((pool) => audioA = pool), ).then((pool) => audioA = pool),
createAudioPool( createAudioPool(
prefixFile(audioAssetB), source:
DeviceFileSource(prefixFile(audioAssetB), mimeType: 'audio/mpeg'),
maxPlayers: 4, maxPlayers: 4,
prefix: '',
).then((pool) => audioB = pool), ).then((pool) => audioB = pool),
], ],
); );
@ -259,8 +255,8 @@ class PinballAudioPlayer {
ConfigureAudioCache? configureAudioCache, ConfigureAudioCache? configureAudioCache,
Random? seed, Random? seed,
}) : _createAudioPool = createAudioPool ?? AudioPool.create, }) : _createAudioPool = createAudioPool ?? AudioPool.create,
_playSingleAudio = playSingleAudio ?? FlameAudio.audioCache.play, _playSingleAudio = playSingleAudio ?? FlameAudio.play,
_loopSingleAudio = loopSingleAudio ?? FlameAudio.audioCache.loop, _loopSingleAudio = loopSingleAudio ?? FlameAudio.loop,
_preCacheSingleAudio = _preCacheSingleAudio =
preCacheSingleAudio ?? FlameAudio.audioCache.load, preCacheSingleAudio ?? FlameAudio.audioCache.load,
_configureAudioCache = configureAudioCache ?? _configureAudioCache = configureAudioCache ??

@ -4,20 +4,21 @@ version: 1.0.0+1
publish_to: none publish_to: none
environment: environment:
sdk: ">=2.16.0 <3.0.0" sdk: "^3.4.3"
dependencies: dependencies:
audioplayers: ^0.20.1 audioplayers: ^6.0.0
clock: ^1.1.0 clock: ^1.1.0
flame_audio: ^1.0.1 equatable: ^2.0.3
flame_audio: ^2.10.2
flutter: flutter:
sdk: flutter sdk: flutter
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mocktail: ^0.3.0 mocktail: ^1.0.4
very_good_analysis: ^2.4.0 very_good_analysis: ^6.0.0
flutter_gen: flutter_gen:
line_length: 80 line_length: 80

@ -1,9 +1,7 @@
// ignore_for_file: prefer_const_constructors, one_member_abstracts // ignore_for_file: prefer_const_constructors, one_member_abstracts
import 'dart:math'; import 'dart:math';
import 'package:audioplayers/audioplayers.dart';
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:flame_audio/audio_pool.dart';
import 'package:flame_audio/flame_audio.dart'; import 'package:flame_audio/flame_audio.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
@ -15,12 +13,11 @@ class _MockAudioPool extends Mock implements AudioPool {}
class _MockAudioCache extends Mock implements AudioCache {} class _MockAudioCache extends Mock implements AudioCache {}
class _MockCreateAudioPool extends Mock { class _MockCreateAudioPool extends Mock {
Future<AudioPool> onCall( Future<AudioPool> onCall({
String sound, { Source source,
bool? repeating, int maxPlayers,
int? maxPlayers, AudioCache? audioCache,
int? minPlayers, int? minPlayers,
String? prefix,
}); });
} }
@ -46,6 +43,20 @@ class _MockRandom extends Mock implements Random {}
class _MockClock extends Mock implements Clock {} class _MockClock extends Mock implements Clock {}
class SourceMatcher extends Matcher {
SourceMatcher(this.path);
final String path;
@override
bool matches(dynamic item, Map matchState) =>
(item as DeviceFileSource).path == path;
@override
Description describe(Description description) =>
description.add('Expected: $path');
}
void main() { void main() {
group('PinballAudio', () { group('PinballAudio', () {
late _MockCreateAudioPool createAudioPool; late _MockCreateAudioPool createAudioPool;
@ -58,15 +69,15 @@ void main() {
setUpAll(() { setUpAll(() {
registerFallbackValue(_MockAudioCache()); registerFallbackValue(_MockAudioCache());
registerFallbackValue(DeviceFileSource('/packages/pinball_audio'));
}); });
setUp(() { setUp(() {
createAudioPool = _MockCreateAudioPool(); createAudioPool = _MockCreateAudioPool();
when( when(
() => createAudioPool.onCall( () => createAudioPool.onCall(
any(), source: any(named: 'source'),
maxPlayers: any(named: 'maxPlayers'), maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
), ),
).thenAnswer((_) async => _MockAudioPool()); ).thenAnswer((_) async => _MockAudioPool());
@ -108,17 +119,23 @@ void main() {
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.bumperA}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.kickerA}'),
),
maxPlayers: 4, maxPlayers: 4,
prefix: '',
), ),
).called(1); ).called(1);
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.bumperB}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.kickerB}'),
),
maxPlayers: 4, maxPlayers: 4,
prefix: '',
), ),
).called(1); ).called(1);
}); });
@ -130,17 +147,23 @@ void main() {
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerA}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.kickerA}'),
),
maxPlayers: 4, maxPlayers: 4,
prefix: '',
), ),
).called(1); ).called(1);
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerB}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.kickerB}'),
),
maxPlayers: 4, maxPlayers: 4,
prefix: '',
), ),
).called(1); ).called(1);
}); });
@ -152,9 +175,12 @@ void main() {
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.flipper}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.flipper}'),
),
maxPlayers: 2, maxPlayers: 2,
prefix: '',
), ),
).called(1); ).called(1);
}); });
@ -242,23 +268,29 @@ void main() {
setUp(() { setUp(() {
bumperAPool = _MockAudioPool(); bumperAPool = _MockAudioPool();
when(() => bumperAPool.start(volume: any(named: 'volume'))) when(() => bumperAPool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {}); .thenAnswer((_) async => () => Future<void>.new(() {}));
when( when(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.bumperA}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.bumperA}'),
),
maxPlayers: any(named: 'maxPlayers'), maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
), ),
).thenAnswer((_) async => bumperAPool); ).thenAnswer((_) async => bumperAPool);
bumperBPool = _MockAudioPool(); bumperBPool = _MockAudioPool();
when(() => bumperBPool.start(volume: any(named: 'volume'))) when(() => bumperBPool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {}); .thenAnswer((_) async => () => Future<void>.new(() {}));
when( when(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.bumperB}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.bumperB}'),
),
maxPlayers: any(named: 'maxPlayers'), maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
), ),
).thenAnswer((_) async => bumperBPool); ).thenAnswer((_) async => bumperBPool);
}); });
@ -295,23 +327,29 @@ void main() {
setUp(() { setUp(() {
kickerAPool = _MockAudioPool(); kickerAPool = _MockAudioPool();
when(() => kickerAPool.start(volume: any(named: 'volume'))) when(() => kickerAPool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {}); .thenAnswer((_) async => () => Future<void>.new(() {}));
when( when(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerA}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.kickerA}'),
),
maxPlayers: any(named: 'maxPlayers'), maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
), ),
).thenAnswer((_) async => kickerAPool); ).thenAnswer((_) async => kickerAPool);
kickerBPool = _MockAudioPool(); kickerBPool = _MockAudioPool();
when(() => kickerBPool.start(volume: any(named: 'volume'))) when(() => kickerBPool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {}); .thenAnswer((_) async => () => Future<void>.new(() {}));
when( when(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.kickerB}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.kickerB}'),
),
maxPlayers: any(named: 'maxPlayers'), maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
), ),
).thenAnswer((_) async => kickerBPool); ).thenAnswer((_) async => kickerBPool);
}); });
@ -347,12 +385,15 @@ void main() {
setUp(() { setUp(() {
pool = _MockAudioPool(); pool = _MockAudioPool();
when(() => pool.start(volume: any(named: 'volume'))) when(() => pool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {}); .thenAnswer((_) async => () => Future<void>.new(() {}));
when( when(
() => createAudioPool.onCall( () => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.flipper}', source: any(
named: 'source',
that:
SourceMatcher('packages/pinball_audio/${Assets.sfx.flipper}'),
),
maxPlayers: any(named: 'maxPlayers'), maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
), ),
).thenAnswer((_) async => pool); ).thenAnswer((_) async => pool);
}); });

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template android_bumper_blinking_behavior} /// {@template android_bumper_blinking_behavior}
/// Makes an [AndroidBumper] blink back to [AndroidBumperState.lit] when /// Makes an [AndroidBumper] blink back to [AndroidBumperState.lit] when

@ -25,7 +25,7 @@ class ArcadeBackground extends Component with ZIndex {
ArcadeBackgroundState>.value( ArcadeBackgroundState>.value(
value: bloc, value: bloc,
children: [ArcadeBackgroundSpriteComponent(assetPath: assetPath)], children: [ArcadeBackgroundSpriteComponent(assetPath: assetPath)],
) ),
], ],
) { ) {
zIndex = ZIndexes.arcadeBackground; zIndex = ZIndexes.arcadeBackground;
@ -45,7 +45,7 @@ class ArcadeBackground extends Component with ZIndex {
ArcadeBackgroundState>.value( ArcadeBackgroundState>.value(
value: bloc ?? ArcadeBackgroundCubit(), value: bloc ?? ArcadeBackgroundCubit(),
children: [ArcadeBackgroundSpriteComponent(assetPath: assetPath)], children: [ArcadeBackgroundSpriteComponent(assetPath: assetPath)],
) ),
], ],
); );

@ -1,5 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/input.dart'; import 'package:flame/events.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
@ -15,7 +15,7 @@ enum ArrowIconDirection {
/// {@template arrow_icon} /// {@template arrow_icon}
/// A [SpriteComponent] that renders a simple arrow icon. /// A [SpriteComponent] that renders a simple arrow icon.
/// {@endtemplate} /// {@endtemplate}
class ArrowIcon extends SpriteComponent with Tappable, HasGameRef { class ArrowIcon extends SpriteComponent with TapCallbacks, HasGameRef {
/// {@macro arrow_icon} /// {@macro arrow_icon}
ArrowIcon({ ArrowIcon({
required Vector2 position, required Vector2 position,
@ -42,7 +42,7 @@ class ArrowIcon extends SpriteComponent with Tappable, HasGameRef {
} }
@override @override
bool onTapUp(TapUpInfo info) { bool onTapUp(TapUpEvent event) {
onTap(); onTap();
return true; return true;
} }

@ -46,7 +46,7 @@ class Ball extends BodyComponent with Layered, InitialPosition, ZIndex {
FlameBlocProvider<BallCubit, BallState>.value( FlameBlocProvider<BallCubit, BallState>.value(
value: bloc ?? BallCubit(), value: bloc ?? BallCubit(),
children: [BallSpriteComponent(assetPath: assetPath)], children: [BallSpriteComponent(assetPath: assetPath)],
) ),
], ],
); );
@ -66,7 +66,7 @@ class Ball extends BodyComponent with Layered, InitialPosition, ZIndex {
bullet: true, bullet: true,
); );
return world.createBody(bodyDef)..createFixtureFromShape(shape, 1); return world.createBody(bodyDef)..createFixtureFromShape(shape);
} }
/// Immediately and completely [stop]s the ball. /// Immediately and completely [stop]s the ball.

@ -3,7 +3,6 @@ import 'dart:math' as math;
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Scales the ball's gravity according to its position on the board. /// Scales the ball's gravity according to its position on the board.
class BallGravitatingBehavior extends Component class BallGravitatingBehavior extends Component

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template ball_impulsing_behavior} /// {@template ball_impulsing_behavior}
/// Impulses the [Ball] in a given direction. /// Impulses the [Ball] in a given direction.
@ -17,6 +16,11 @@ class BallImpulsingBehavior extends Component with ParentIsA<Ball> {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
parent.body.linearVelocity = _impulse; parent.body.linearVelocity = _impulse;
shouldRemove = true; }
@override
void onMount() {
super.onMount();
parent.remove(this);
} }
} }

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Scales the ball's body and sprite according to its position on the board. /// Scales the ball's body and sprite according to its position on the board.
class BallScalingBehavior extends Component with ParentIsA<Ball> { class BallScalingBehavior extends Component with ParentIsA<Ball> {

@ -21,7 +21,7 @@ class Boundaries extends Component {
/// {@template bottom_boundary} /// {@template bottom_boundary}
/// Curved boundary at the bottom of the board where the [Ball] exits the field /// Curved boundary at the bottom of the board where the [Ball] exits the field
/// of play. /// of play.
/// {@endtemplate bottom_boundary} /// {@endtemplate}
class _BottomBoundary extends BodyComponent with InitialPosition, ZIndex { class _BottomBoundary extends BodyComponent with InitialPosition, ZIndex {
/// {@macro bottom_boundary} /// {@macro bottom_boundary}
_BottomBoundary() _BottomBoundary()
@ -89,7 +89,7 @@ class _BottomBoundarySpriteComponent extends SpriteComponent with HasGameRef {
/// ///
/// The right side of the board is closed by the barrier the [LaunchRamp] /// The right side of the board is closed by the barrier the [LaunchRamp]
/// creates. /// creates.
/// {@endtemplate outer_boundary} /// {@endtemplate}
class _OuterBoundary extends BodyComponent with InitialPosition, ZIndex { class _OuterBoundary extends BodyComponent with InitialPosition, ZIndex {
/// {@macro outer_boundary} /// {@macro outer_boundary}
_OuterBoundary() _OuterBoundary()

@ -28,17 +28,18 @@ class CameraZoom extends Effect with HasGameRef {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
_tween = Tween( _tween = Tween(
begin: gameRef.camera.zoom, begin: gameRef.camera.viewfinder.zoom,
end: value, end: value,
); );
} }
@override @override
void apply(double progress) { void apply(double progress) {
gameRef.camera.zoom = _tween.transform(progress); gameRef.camera.viewfinder.zoom = _tween.transform(progress);
} }
/// Returns a [Future] that completes once the zoom is finished /// Returns a [Future] that completes once the zoom is finished
@override
Future<void> get completed { Future<void> get completed {
if (controller.completed) { if (controller.completed) {
return Future.value(); return Future.value();

@ -12,7 +12,7 @@ class ChromeDinoMouthOpeningBehavior extends ContactBehavior<ChromeDino> {
if (other is! Ball) return; if (other is! Ball) return;
if (parent.bloc.state.isMouthOpen && parent.firstChild<Ball>() == null) { if (parent.bloc.state.isMouthOpen && parent.firstChild<Ball>() == null) {
contact.setEnabled(false); contact.isEnabled = false;
} }
} }
} }

@ -1,7 +1,6 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template chrome_dino_spitting_behavior} /// {@template chrome_dino_spitting_behavior}
/// Spits the [Ball] from the [ChromeDino] the next time the mouth opens. /// Spits the [Ball] from the [ChromeDino] the next time the mouth opens.

@ -1,7 +1,6 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template chrome_dino_swivel_behavior} /// {@template chrome_dino_swivel_behavior}
/// Swivels the [ChromeDino] up and down periodically to match its animation /// Swivels the [ChromeDino] up and down periodically to match its animation
@ -51,7 +50,7 @@ class ChromeDinoSwivelingBehavior extends TimerComponent
@override @override
void onTick() { void onTick() {
super.onTick(); super.onTick();
_joint.setMotorSpeed(-_joint.motorSpeed); _joint.motorSpeed = -_joint.motorSpeed;
} }
} }
@ -63,8 +62,8 @@ class _ChromeDinoAnchor extends JointAnchor
parent.parent.children parent.parent.children
.whereType<SpriteAnimationComponent>() .whereType<SpriteAnimationComponent>()
.forEach((sprite) { .forEach((sprite) {
sprite.animation!.currentIndex = 45; sprite.animationTicker!.currentIndex = 45;
sprite.changeParent(this); sprite.parent = this;
}); });
} }
} }

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart' hide Timer; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/chrome_dino/behaviors/behaviors.dart'; import 'package:pinball_components/src/components/chrome_dino/behaviors/behaviors.dart';

@ -7,7 +7,7 @@ class DashBumpersState extends Equatable {
: this( : this(
bumperSpriteStates: { bumperSpriteStates: {
for (var id in DashBumperId.values) for (var id in DashBumperId.values)
id: DashBumperSpriteState.inactive id: DashBumperSpriteState.inactive,
}, },
); );

@ -51,7 +51,7 @@ class ErrorComponent extends SpriteComponent with HasGameRef {
while (words.isNotEmpty) { while (words.isNotEmpty) {
final word = words.removeAt(0); final word = words.removeAt(0);
if (_textPaint.measureTextWidth('$currentLine $word') <= maxWidth) { if (_textPaint.getLineMetrics('$currentLine $word').width <= maxWidth) {
currentLine = '$currentLine $word'.trim(); currentLine = '$currentLine $word'.trim();
} else { } else {
lines.add(currentLine); lines.add(currentLine);

@ -161,10 +161,11 @@ class FlapSpriteAnimationComponent extends SpriteAnimationComponent
textureSize: textureSize, textureSize: textureSize,
loop: false, loop: false,
), ),
)..onComplete = () { );
animation?.reset(); animationTicker?.onComplete = () {
playing = false; animationTicker?.reset();
}; playing = false;
};
} }
} }

@ -1,7 +1,6 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Joints the [Flipper] to allow pivoting around one end. /// Joints the [Flipper] to allow pivoting around one end.
class FlipperJointingBehavior extends Component class FlipperJointingBehavior extends Component

@ -33,14 +33,14 @@ class FlipperKeyControllingBehavior extends Component
@override @override
bool onKeyEvent( bool onKeyEvent(
RawKeyEvent event, KeyEvent event,
Set<LogicalKeyboardKey> keysPressed, Set<LogicalKeyboardKey> keysPressed,
) { ) {
if (!_keys.contains(event.logicalKey)) return true; if (!_keys.contains(event.logicalKey)) return true;
if (event is RawKeyDownEvent) { if (event is KeyDownEvent) {
bloc.moveUp(); bloc.moveUp();
} else if (event is RawKeyUpEvent) { } else if (event is KeyUpEvent) {
bloc.moveDown(); bloc.moveDown();
} }

@ -13,7 +13,7 @@ export 'cubit/flipper_cubit.dart';
/// A bat, typically found in pairs at the bottom of the board. /// A bat, typically found in pairs at the bottom of the board.
/// ///
/// [Flipper] can be controlled by the player in an arc motion. /// [Flipper] can be controlled by the player in an arc motion.
/// {@endtemplate flipper} /// {@endtemplate}
class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
/// {@macro flipper} /// {@macro flipper}
Flipper({ Flipper({

@ -105,9 +105,10 @@ class _PinSpriteAnimationComponent extends SpriteAnimationComponent
textureSize: textureSize, textureSize: textureSize,
loop: false, loop: false,
), ),
)..onComplete = () { );
animation?.reset(); animationTicker?.onComplete = () {
playing = false; animationTicker?.reset();
}; playing = false;
};
} }
} }

@ -18,7 +18,7 @@ class GoogleWordAnimatingBehavior extends TimerComponent
} else { } else {
timer.stop(); timer.stop();
bloc.onReset(); bloc.onReset();
shouldRemove = true; parent?.remove(this);
} }
} }
} }

@ -33,7 +33,7 @@ class GoogleWordCubit extends Cubit<GoogleWordState> {
if (i.isEven) if (i.isEven)
i: GoogleLetterSpriteState.dimmed i: GoogleLetterSpriteState.dimmed
else else
i: GoogleLetterSpriteState.lit i: GoogleLetterSpriteState.lit,
}, },
), ),
); );
@ -46,7 +46,7 @@ class GoogleWordCubit extends Cubit<GoogleWordState> {
if (i.isEven) if (i.isEven)
i: GoogleLetterSpriteState.lit i: GoogleLetterSpriteState.lit
else else
i: GoogleLetterSpriteState.dimmed i: GoogleLetterSpriteState.dimmed,
}, },
), ),
); );
@ -62,7 +62,7 @@ class GoogleWordCubit extends Cubit<GoogleWordState> {
if (i.isEven) if (i.isEven)
i: GoogleLetterSpriteState.lit i: GoogleLetterSpriteState.lit
else else
i: GoogleLetterSpriteState.dimmed i: GoogleLetterSpriteState.dimmed,
}, },
), ),
); );

@ -6,7 +6,7 @@ class GoogleWordState extends Equatable {
GoogleWordState.initial() GoogleWordState.initial()
: this( : this(
letterSpriteStates: { letterSpriteStates: {
for (var i = 0; i <= 5; i++) i: GoogleLetterSpriteState.dimmed for (var i = 0; i <= 5; i++) i: GoogleLetterSpriteState.dimmed,
}, },
); );

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template kicker_blinking_behavior} /// {@template kicker_blinking_behavior}
/// Makes a [Kicker] blink back to [KickerState.lit] when [KickerState.dimmed]. /// Makes a [Kicker] blink back to [KickerState.lit] when [KickerState.dimmed].

@ -8,7 +8,6 @@ import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets; import 'package:pinball_components/pinball_components.dart' hide Assets;
import 'package:pinball_components/src/components/bumping_behavior.dart'; import 'package:pinball_components/src/components/bumping_behavior.dart';
import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart'; import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart';
import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/kicker_cubit.dart'; export 'cubit/kicker_cubit.dart';
@ -17,7 +16,7 @@ export 'cubit/kicker_cubit.dart';
/// opposite side. /// opposite side.
/// ///
/// [Kicker]s are usually positioned above each [Flipper]. /// [Kicker]s are usually positioned above each [Flipper].
/// {@endtemplate kicker} /// {@endtemplate}
class Kicker extends BodyComponent with InitialPosition { class Kicker extends BodyComponent with InitialPosition {
/// {@macro kicker} /// {@macro kicker}
Kicker({ Kicker({

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template multiball_blinking_behavior} /// {@template multiball_blinking_behavior}
/// Makes a [Multiball] blink back to [MultiballLightState.lit] when /// Makes a [Multiball] blink back to [MultiballLightState.lit] when

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/gen/assets.gen.dart'; import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/src/components/multiball/behaviors/behaviors.dart'; import 'package:pinball_components/src/components/multiball/behaviors/behaviors.dart';
import 'package:pinball_components/src/pinball_components.dart'; import 'package:pinball_components/src/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/multiball_cubit.dart'; export 'cubit/multiball_cubit.dart';

@ -2,7 +2,6 @@ import 'package:flame/components.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball_components/gen/assets.gen.dart'; import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/src/components/multiplier/cubit/multiplier_cubit.dart'; import 'package:pinball_components/src/components/multiplier/cubit/multiplier_cubit.dart';
import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/multiplier_cubit.dart'; export 'cubit/multiplier_cubit.dart';

@ -1,7 +1,6 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class PlungerJointingBehavior extends Component with ParentIsA<Plunger> { class PlungerJointingBehavior extends Component with ParentIsA<Plunger> {
PlungerJointingBehavior({required double compressionDistance}) PlungerJointingBehavior({required double compressionDistance})

@ -17,14 +17,14 @@ class PlungerKeyControllingBehavior extends Component
@override @override
bool onKeyEvent( bool onKeyEvent(
RawKeyEvent event, KeyEvent event,
Set<LogicalKeyboardKey> keysPressed, Set<LogicalKeyboardKey> keysPressed,
) { ) {
if (!_keys.contains(event.logicalKey)) return true; if (!_keys.contains(event.logicalKey)) return true;
if (event is RawKeyDownEvent) { if (event is KeyDownEvent) {
bloc.pulled(); bloc.pulled();
} else if (event is RawKeyUpEvent) { } else if (event is KeyUpEvent) {
bloc.released(); bloc.released();
} }

@ -99,7 +99,7 @@ class _PlungerSpriteAnimationGroupComponent
final startedReleasing = state.isReleasing && !current!.isReleasing; final startedReleasing = state.isReleasing && !current!.isReleasing;
final startedPulling = state.isPulling && !current!.isPulling; final startedPulling = state.isPulling && !current!.isPulling;
if (startedReleasing || startedPulling) { if (startedReleasing || startedPulling) {
animation?.reset(); animationTicker?.reset();
} }
current = state; current = state;

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Scales a [ScoreComponent] according to its position on the board. /// Scales a [ScoreComponent] according to its position on the board.
class ScoreComponentScalingBehavior extends Component class ScoreComponentScalingBehavior extends Component

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template skill_shot_blinking_behavior} /// {@template skill_shot_blinking_behavior}
/// Makes a [SkillShot] blink between [SkillShotSpriteState.lit] and /// Makes a [SkillShot] blink between [SkillShotSpriteState.lit] and

@ -127,10 +127,11 @@ class PinSpriteAnimationComponent extends SpriteAnimationComponent
textureSize: textureSize, textureSize: textureSize,
loop: false, loop: false,
), ),
)..onComplete = () { );
animation?.reset(); animationTicker?.onComplete = () {
playing = false; animationTicker?.reset();
}; playing = false;
};
} }
} }

@ -15,7 +15,7 @@ class SpaceshipRail extends Component {
children: [ children: [
_SpaceshipRail(), _SpaceshipRail(),
_SpaceshipRailExit(), _SpaceshipRailExit(),
_SpaceshipRailExitSpriteComponent() _SpaceshipRailExitSpriteComponent(),
], ],
); );
} }

@ -430,7 +430,7 @@ class SpaceshipRampBase extends BodyComponent
// Although, the Layer should already be taking care of the contact // Although, the Layer should already be taking care of the contact
// filtering, this is to ensure the ball doesn't collide with the ramp base // filtering, this is to ensure the ball doesn't collide with the ramp base
// when the filtering is calculated on different time steps. // when the filtering is calculated on different time steps.
contact.setEnabled(other.layer == Layer.board); contact.isEnabled = other.layer == Layer.board;
} }
@override @override

@ -1,6 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template sparky_bumper_blinking_behavior} /// {@template sparky_bumper_blinking_behavior}
/// Makes a [SparkyBumper] blink back to [SparkyBumperState.lit] when /// Makes a [SparkyBumper] blink back to [SparkyBumperState.lit] when

@ -4,20 +4,16 @@ version: 1.0.0+1
publish_to: none publish_to: none
environment: environment:
sdk: ">=2.16.0 <3.0.0" sdk: "^3.4.3"
dependencies: dependencies:
bloc: ^8.0.3 bloc: ^8.0.3
flame: ^1.1.1 flame: ^1.18.0
flame_bloc: ^1.4.0 flame_bloc: ^1.12.0
flame_forge2d: flame_forge2d: ^0.18.1
git:
url: https://github.com/flame-engine/flame
path: packages/flame_forge2d/
ref: a50d4a1e7d9eaf66726ed1bb9894c9d495547d8f
flutter: flutter:
sdk: flutter sdk: flutter
intl: ^0.17.0 intl: ^0.19.0
pinball_audio: pinball_audio:
path: ../pinball_audio path: ../pinball_audio
pinball_flame: pinball_flame:
@ -32,8 +28,8 @@ dev_dependencies:
flame_test: ^1.3.0 flame_test: ^1.3.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mocktail: ^0.2.0 mocktail: ^1.0.4
very_good_analysis: ^2.4.0 very_good_analysis: ^6.0.0
flutter: flutter:
uses-material-design: true uses-material-design: true

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/input.dart'; import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -18,7 +19,7 @@ abstract class AssetsGame extends Forge2DGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
if (_imagesFileNames != null) { if (_imagesFileNames != null) {
await images.loadAll(_imagesFileNames!); await images.loadAll(_imagesFileNames);
} }
} }
} }
@ -37,19 +38,18 @@ abstract class LineGame extends AssetsGame with PanDetector {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.follow(PositionComponent(position: Vector2.zero()));
camera.followVector2(Vector2.zero()); add(_PreviewLine());
unawaited(add(_PreviewLine()));
} }
@override @override
void onPanStart(DragStartInfo info) { void onPanStart(DragStartInfo info) {
_lineEnd = info.eventPosition.game; _lineEnd = info.eventPosition.global;
} }
@override @override
void onPanUpdate(DragUpdateInfo info) { void onPanUpdate(DragUpdateInfo info) {
_lineEnd = info.eventPosition.game; _lineEnd = info.eventPosition.global;
} }
@override @override

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/extensions.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -23,7 +23,7 @@ class AndroidBumperAGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add( await add(
AndroidBumper.a()..priority = 1, AndroidBumper.a()..priority = 1,
); );

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/extensions.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -23,7 +23,7 @@ class AndroidBumperBGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add( await add(
AndroidBumper.b()..priority = 1, AndroidBumper.b()..priority = 1,
); );

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/extensions.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -23,7 +23,7 @@ class AndroidBumperCowGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add( await add(
AndroidBumper.cow()..priority = 1, AndroidBumper.cow()..priority = 1,
); );

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/input.dart'; import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
@ -29,7 +29,7 @@ class AndroidSpaceshipGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add( await add(
FlameBlocProvider<AndroidSpaceshipCubit, AndroidSpaceshipState>( FlameBlocProvider<AndroidSpaceshipCubit, AndroidSpaceshipState>(
create: AndroidSpaceshipCubit.new, create: AndroidSpaceshipCubit.new,

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/input.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -27,7 +27,7 @@ class SpaceshipRailGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2(-30, -10)); camera.follow(PositionComponent(position: Vector2(-30, -10)));
await add(SpaceshipRail()); await add(SpaceshipRail());
await ready(); await ready();
await traceAllBodies(); await traceAllBodies();

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame/input.dart'; import 'package:flame/input.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -43,7 +44,7 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2(-12, -50)); camera.follow(PositionComponent(position: Vector2(-12, -50)));
_spaceshipRamp = SpaceshipRamp(); _spaceshipRamp = SpaceshipRamp();
await add(_spaceshipRamp); await add(_spaceshipRamp);
@ -52,11 +53,10 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents {
@override @override
KeyEventResult onKeyEvent( KeyEventResult onKeyEvent(
RawKeyEvent event, KeyEvent event,
Set<LogicalKeyboardKey> keysPressed, Set<LogicalKeyboardKey> keysPressed,
) { ) {
if (event is RawKeyDownEvent && if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.space) {
event.logicalKey == LogicalKeyboardKey.space) {
_spaceshipRamp _spaceshipRamp
.readBloc<SpaceshipRampCubit, SpaceshipRampState>() .readBloc<SpaceshipRampCubit, SpaceshipRampState>()
.onProgressed(); .onProgressed();

@ -1,8 +1,9 @@
import 'package:flame/game.dart'; import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/games.dart'; import 'package:sandbox/common/games.dart';
class ArrowIconGame extends AssetsGame with HasTappables { class ArrowIconGame extends AssetsGame with TapCallbacks {
ArrowIconGame() ArrowIconGame()
: super( : super(
imagesFileNames: [ imagesFileNames: [
@ -16,7 +17,7 @@ class ArrowIconGame extends AssetsGame with HasTappables {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add( await add(
ArrowIcon( ArrowIcon(

@ -1,4 +1,4 @@
import 'package:flame/input.dart'; import 'package:flame/events.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_theme/pinball_theme.dart' as theme; import 'package:pinball_theme/pinball_theme.dart' as theme;
@ -43,7 +43,7 @@ class BallGame extends AssetsGame with TapDetector, Traceable {
Ball( Ball(
assetPath: characterBallPaths[character], assetPath: characterBallPaths[character],
) )
..initialPosition = info.eventPosition.game ..initialPosition = info.eventPosition.global
..layer = ballLayer ..layer = ballLayer
..priority = ballPriority, ..priority = ballPriority,
); );

@ -21,8 +21,7 @@ class BaseboardGame extends BallGame {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final center = screenToWorld(camera.viewport.size / 2);
final center = screenToWorld(camera.viewport.canvasSize! / 2);
await addAll([ await addAll([
Baseboard(side: BoardSide.left) Baseboard(side: BoardSide.left)
..initialPosition = center - Vector2(25, 0) ..initialPosition = center - Vector2(25, 0)

@ -28,7 +28,7 @@ class FlipperGame extends BallGame with KeyboardEvents {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2); final center = screenToWorld(camera.viewport.size / 2);
await addAll([ await addAll([
leftFlipper = Flipper(side: BoardSide.left) leftFlipper = Flipper(side: BoardSide.left)
..initialPosition = center - Vector2(Flipper.size.x, 0), ..initialPosition = center - Vector2(Flipper.size.x, 0),

@ -24,7 +24,7 @@ class KickerGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2); final center = screenToWorld(camera.viewport.size / 2);
await addAll( await addAll(
[ [
Kicker(side: BoardSide.left) Kicker(side: BoardSide.left)

@ -1,4 +1,4 @@
import 'package:flame/extensions.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -24,8 +24,8 @@ class BoundariesGame extends BallGame {
await super.onLoad(); await super.onLoad();
camera camera
..followVector2(Vector2.zero()) ..follow(PositionComponent(position: Vector2.zero()))
..zoom = 6; ..viewfinder.zoom = 6;
await add(Boundaries()); await add(Boundaries());
await ready(); await ready();
await traceAllBodies(); await traceAllBodies();

@ -1,4 +1,4 @@
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -22,7 +22,7 @@ class ChromeDinoGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add(ChromeDino()); await add(ChromeDino());
await traceAllBodies(); await traceAllBodies();

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flame/input.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -25,7 +25,7 @@ class DinoWallsGame extends BallGame {
]); ]);
await add(DinoWalls()); await add(DinoWalls());
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await traceAllBodies(); await traceAllBodies();
} }
} }

@ -1,4 +1,4 @@
import 'package:flame/extensions.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
@ -22,7 +22,7 @@ class SlingshotsGame extends BallGame {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add(Slingshots()); await add(Slingshots());
await ready(); await ready();
await traceAllBodies(); await traceAllBodies();

@ -24,7 +24,7 @@ class CameraZoomGame extends AssetsGame with TapDetector {
), ),
); );
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
} }
@override @override

@ -11,7 +11,7 @@ class ErrorComponentGame extends AssetsGame {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
camera.followVector2(Vector2.zero()); camera.follow(PositionComponent(position: Vector2.zero()));
await add(ErrorComponent(label: text)); await add(ErrorComponent(label: text));
await add( await add(

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

Loading…
Cancel
Save