Flutter 3.22 (#505)

## Description

Updates dependencies in general for the code to be able to build with
the latest version of flutter and dart.

## Type of Change

- [ ]  New feature (non-breaking change which adds functionality)
- [x] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [x]  Breaking change (fix or feature that would cause existing
functionality to change)
- [x] 🧹 Code refactor
- [x]  Build configuration change
- [x] 📝 Documentation
- [x] 🗑️ Chore
pull/502/head
Álvaro Stivi 2 months ago committed by GitHub
parent 0c21af0e2d
commit 1c6a3cde65
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
with:
flutter_channel: stable
flutter_version: 2.10.5
flutter_version: 3.22.2
coverage_excludes: "lib/gen/*.dart"
test_optimization: false

6
.gitignore vendored

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

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

@ -19,6 +19,17 @@ _Created using [Very Good CLI][very_good_cli_link] 🤖_
## 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:
```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
/// the UI paint first, and then we start loading the assets.
await Future<void>.delayed(const Duration(seconds: 1));
if (isClosed) return;
final loadables = <Future<void> Function()>[
_game.preFetchLeaderboard,
..._game.preLoadAssets(),

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

@ -1,10 +1,6 @@
import 'dart:async';
import 'dart:developer';
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 {
@override
@ -19,30 +15,3 @@ class AppBlocObserver extends BlocObserver {
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:pinball_flame/pinball_flame.dart';
class AnimatronicLoopingBehavior extends TimerComponent
with ParentIsA<SpriteAnimationComponent> {
@ -10,8 +9,8 @@ class AnimatronicLoopingBehavior extends TimerComponent
@override
Future<void> onLoad() async {
await super.onLoad();
parent.animation?.onComplete = () {
parent.animation?.reset();
parent.animationTicker?.onComplete = () {
parent.animationTicker?.reset();
parent.playing = false;
timer
..reset()

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

@ -53,7 +53,11 @@ class Backbox extends PositionComponent with ZIndex, HasGameRef {
_build(_bloc.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);
});
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,28 +1,41 @@
import 'dart:async';
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:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart';
import 'package:pinball/app/app.dart';
import 'package:pinball/bootstrap.dart';
import 'package:pinball/firebase_options.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:platform_helper/platform_helper.dart';
import 'package:share_repository/share_repository.dart';
void main() {
bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore);
const shareRepository =
ShareRepository(appUrl: ShareRepository.pinballGameUrl);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudioPlayer = PinballAudioPlayer();
final platformHelper = PlatformHelper();
await Firebase.initializeApp();
await authenticationRepository.authenticateAnonymously();
return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository,
shareRepository: shareRepository,
pinballAudioPlayer: pinballAudioPlayer,
platformHelper: platformHelper,
);
});
Future<App> bootstrap() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
final leaderboardRepository =
LeaderboardRepository(FirebaseFirestore.instance);
const shareRepository =
ShareRepository(appUrl: ShareRepository.pinballGameUrl);
final authenticationRepository =
AuthenticationRepository(FirebaseAuth.instance);
final pinballAudioPlayer = PinballAudioPlayer();
final platformHelper = PlatformHelper();
await authenticationRepository.authenticateAnonymously();
return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository,
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>(
context: context,
barrierColor: PinballColors.transparent,
barrierDismissible: true,
builder: (_) {
return Center(
child: SizedBox(
@ -32,11 +31,11 @@ class MoreInformationDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
return const Material(
color: PinballColors.transparent,
child: _LinkBoxDecoration(
child: Column(
children: const [
children: [
SizedBox(height: 16),
_LinkBoxHeader(),
Expanded(
@ -59,7 +58,7 @@ class _LinkBoxHeader extends StatelessWidget {
children: [
Text(
l10n.linkBoxTitle,
style: Theme.of(context).textTheme.headline3!.copyWith(
style: Theme.of(context).textTheme.displaySmall!.copyWith(
color: PinballColors.blue,
fontWeight: FontWeight.bold,
),
@ -77,9 +76,8 @@ class _LinkBoxHeader extends StatelessWidget {
class _LinkBoxDecoration extends StatelessWidget {
const _LinkBoxDecoration({
Key? key,
required this.child,
}) : super(key: key);
});
final Widget child;
@ -156,7 +154,7 @@ class _TextLink extends StatelessWidget {
onTap: () => openLink(link),
child: Text(
text,
style: theme.textTheme.headline5!.copyWith(
style: theme.textTheme.headlineSmall!.copyWith(
color: PinballColors.white,
),
overflow: TextOverflow.ellipsis,
@ -176,7 +174,8 @@ class _MadeWithFlutterAndFirebase extends StatelessWidget {
textAlign: TextAlign.center,
text: TextSpan(
text: l10n.linkBoxMadeWithText,
style: theme.textTheme.headline5!.copyWith(color: PinballColors.white),
style:
theme.textTheme.headlineSmall!.copyWith(color: PinballColors.white),
children: <TextSpan>[
TextSpan(
text: l10n.linkBoxFlutterLinkText,
@ -191,7 +190,7 @@ class _MadeWithFlutterAndFirebase extends StatelessWidget {
text: l10n.linkBoxFirebaseLinkText,
recognizer: TapGestureRecognizer()
..onTap = () => openLink(_MoreInformationUrl.firebaseWebsite),
style: theme.textTheme.headline5!.copyWith(
style: theme.textTheme.headlineSmall!.copyWith(
decoration: TextDecoration.underline,
),
),

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,6 +1,5 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template ball_impulsing_behavior}
/// Impulses the [Ball] in a given direction.
@ -17,6 +16,11 @@ class BallImpulsingBehavior extends Component with ParentIsA<Ball> {
Future<void> onLoad() async {
await super.onLoad();
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: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.
class BallScalingBehavior extends Component with ParentIsA<Ball> {

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

@ -28,17 +28,18 @@ class CameraZoom extends Effect with HasGameRef {
@override
Future<void> onLoad() async {
_tween = Tween(
begin: gameRef.camera.zoom,
begin: gameRef.camera.viewfinder.zoom,
end: value,
);
}
@override
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
@override
Future<void> get completed {
if (controller.completed) {
return Future.value();

@ -12,7 +12,7 @@ class ChromeDinoMouthOpeningBehavior extends ContactBehavior<ChromeDino> {
if (other is! Ball) return;
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_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template chrome_dino_spitting_behavior}
/// Spits the [Ball] from the [ChromeDino] the next time the mouth opens.

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

@ -1,7 +1,7 @@
import 'dart:async';
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:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/chrome_dino/behaviors/behaviors.dart';

@ -7,7 +7,7 @@ class DashBumpersState extends Equatable {
: this(
bumperSpriteStates: {
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) {
final word = words.removeAt(0);
if (_textPaint.measureTextWidth('$currentLine $word') <= maxWidth) {
if (_textPaint.getLineMetrics('$currentLine $word').width <= maxWidth) {
currentLine = '$currentLine $word'.trim();
} else {
lines.add(currentLine);

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

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

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

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

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

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

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

@ -6,7 +6,7 @@ class GoogleWordState extends Equatable {
GoogleWordState.initial()
: this(
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:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template kicker_blinking_behavior}
/// 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/src/components/bumping_behavior.dart';
import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart';
import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/kicker_cubit.dart';
@ -17,7 +16,7 @@ export 'cubit/kicker_cubit.dart';
/// opposite side.
///
/// [Kicker]s are usually positioned above each [Flipper].
/// {@endtemplate kicker}
/// {@endtemplate}
class Kicker extends BodyComponent with InitialPosition {
/// {@macro kicker}
Kicker({

@ -1,6 +1,5 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template multiball_blinking_behavior}
/// 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/src/components/multiball/behaviors/behaviors.dart';
import 'package:pinball_components/src/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/multiball_cubit.dart';

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

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

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

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

@ -1,6 +1,5 @@
import 'package:flame/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.
class ScoreComponentScalingBehavior extends Component

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

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

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

@ -430,7 +430,7 @@ class SpaceshipRampBase extends BodyComponent
// 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
// when the filtering is calculated on different time steps.
contact.setEnabled(other.layer == Layer.board);
contact.isEnabled = other.layer == Layer.board;
}
@override

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

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

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

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

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

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

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

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

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -43,7 +44,7 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents {
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2(-12, -50));
camera.follow(PositionComponent(position: Vector2(-12, -50)));
_spaceshipRamp = SpaceshipRamp();
await add(_spaceshipRamp);
@ -52,11 +53,10 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents {
@override
KeyEventResult onKeyEvent(
RawKeyEvent event,
KeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.space) {
if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.space) {
_spaceshipRamp
.readBloc<SpaceshipRampCubit, SpaceshipRampState>()
.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:sandbox/common/games.dart';
class ArrowIconGame extends AssetsGame with HasTappables {
class ArrowIconGame extends AssetsGame with TapCallbacks {
ArrowIconGame()
: super(
imagesFileNames: [
@ -16,7 +17,7 @@ class ArrowIconGame extends AssetsGame with HasTappables {
@override
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
camera.follow(PositionComponent(position: Vector2.zero()));
await add(
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_flame/pinball_flame.dart';
import 'package:pinball_theme/pinball_theme.dart' as theme;
@ -43,7 +43,7 @@ class BallGame extends AssetsGame with TapDetector, Traceable {
Ball(
assetPath: characterBallPaths[character],
)
..initialPosition = info.eventPosition.game
..initialPosition = info.eventPosition.global
..layer = ballLayer
..priority = ballPriority,
);

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

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

@ -24,7 +24,7 @@ class KickerGame extends BallGame {
Future<void> onLoad() async {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final center = screenToWorld(camera.viewport.size / 2);
await addAll(
[
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:sandbox/stories/ball/basic_ball_game.dart';
@ -24,8 +24,8 @@ class BoundariesGame extends BallGame {
await super.onLoad();
camera
..followVector2(Vector2.zero())
..zoom = 6;
..follow(PositionComponent(position: Vector2.zero()))
..viewfinder.zoom = 6;
await add(Boundaries());
await ready();
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:sandbox/stories/ball/basic_ball_game.dart';
@ -22,7 +22,7 @@ class ChromeDinoGame extends BallGame {
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
camera.follow(PositionComponent(position: Vector2.zero()));
await add(ChromeDino());
await traceAllBodies();

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

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

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

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

Loading…
Cancel
Save