Merge branch 'main' into feat/kicker-blinking-assets

pull/283/head
Allison Ryan 3 years ago
commit 1641fae88e

@ -0,0 +1,22 @@
name: authentication_repository
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
paths:
- "packages/authentication_repository/**"
- ".github/workflows/authentication_repository.yaml"
pull_request:
paths:
- "packages/authentication_repository/**"
- ".github/workflows/authentication_repository.yaml"
jobs:
build:
uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1
with:
working_directory: packages/authentication_repository

@ -7,6 +7,7 @@
// ignore_for_file: public_member_api_docs // ignore_for_file: public_member_api_docs
import 'package:authentication_repository/authentication_repository.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
@ -15,16 +16,20 @@ import 'package:pinball/game/game.dart';
import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/l10n/l10n.dart';
import 'package:pinball/select_character/select_character.dart'; import 'package:pinball/select_character/select_character.dart';
import 'package:pinball_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_ui/pinball_ui.dart';
class App extends StatelessWidget { class App extends StatelessWidget {
const App({ const App({
Key? key, Key? key,
required AuthenticationRepository authenticationRepository,
required LeaderboardRepository leaderboardRepository, required LeaderboardRepository leaderboardRepository,
required PinballAudio pinballAudio, required PinballAudio pinballAudio,
}) : _leaderboardRepository = leaderboardRepository, }) : _authenticationRepository = authenticationRepository,
_leaderboardRepository = leaderboardRepository,
_pinballAudio = pinballAudio, _pinballAudio = pinballAudio,
super(key: key); super(key: key);
final AuthenticationRepository _authenticationRepository;
final LeaderboardRepository _leaderboardRepository; final LeaderboardRepository _leaderboardRepository;
final PinballAudio _pinballAudio; final PinballAudio _pinballAudio;
@ -32,19 +37,21 @@ class App extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiRepositoryProvider( return MultiRepositoryProvider(
providers: [ providers: [
RepositoryProvider.value(value: _authenticationRepository),
RepositoryProvider.value(value: _leaderboardRepository), RepositoryProvider.value(value: _leaderboardRepository),
RepositoryProvider.value(value: _pinballAudio), RepositoryProvider.value(value: _pinballAudio),
], ],
child: BlocProvider( child: BlocProvider(
create: (context) => CharacterThemeCubit(), create: (context) => CharacterThemeCubit(),
child: const MaterialApp( child: MaterialApp(
title: 'I/O Pinball', title: 'I/O Pinball',
localizationsDelegates: [ theme: PinballTheme.standard,
localizationsDelegates: const [
AppLocalizations.delegate, AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
], ],
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
home: PinballGamePage(), home: const PinballGamePage(),
), ),
), ),
); );

@ -12,6 +12,7 @@ import 'dart:developer';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class AppBlocObserver extends BlocObserver { class AppBlocObserver extends BlocObserver {
@ -28,9 +29,12 @@ class AppBlocObserver extends BlocObserver {
} }
} }
Future<void> bootstrap( typedef BootstrapBuilder = Future<Widget> Function(
Future<Widget> Function(FirebaseFirestore firestore) builder, FirebaseFirestore firestore,
) async { FirebaseAuth firebaseAuth,
);
Future<void> bootstrap(BootstrapBuilder builder) async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
FlutterError.onError = (details) { FlutterError.onError = (details) {
log(details.exceptionAsString(), stackTrace: details.stack); log(details.exceptionAsString(), stackTrace: details.stack);
@ -39,7 +43,12 @@ Future<void> bootstrap(
await runZonedGuarded( await runZonedGuarded(
() async { () async {
await BlocOverrides.runZoned( await BlocOverrides.runZoned(
() async => runApp(await builder(FirebaseFirestore.instance)), () async => runApp(
await builder(
FirebaseFirestore.instance,
FirebaseAuth.instance,
),
),
blocObserver: AppBlocObserver(), blocObserver: AppBlocObserver(),
); );
}, },

@ -0,0 +1,76 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_ui/pinball_ui.dart';
/// {@template footer}
/// Footer widget with links to the main tech stack.
/// {@endtemplate}
class Footer extends StatelessWidget {
/// {@macro footer}
const Footer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(50, 0, 50, 32),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
_MadeWithFlutterAndFirebase(),
_GoogleIO(),
],
),
);
}
}
class _GoogleIO extends StatelessWidget {
const _GoogleIO({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final theme = Theme.of(context);
return Text(
l10n.footerGoogleIOText,
style: theme.textTheme.bodyText1!.copyWith(color: PinballColors.white),
);
}
}
class _MadeWithFlutterAndFirebase extends StatelessWidget {
const _MadeWithFlutterAndFirebase({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final theme = Theme.of(context);
return RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: l10n.footerMadeWithText,
style: theme.textTheme.bodyText1!.copyWith(color: PinballColors.white),
children: <TextSpan>[
TextSpan(
text: l10n.footerFlutterLinkText,
recognizer: TapGestureRecognizer()
..onTap = () => openLink('https://flutter.dev'),
style: const TextStyle(
decoration: TextDecoration.underline,
),
),
const TextSpan(text: ' & '),
TextSpan(
text: l10n.footerFirebaseLinkText,
recognizer: TapGestureRecognizer()
..onTap = () => openLink('https://firebase.google.com'),
style: const TextStyle(
decoration: TextDecoration.underline,
),
),
],
),
);
}
}

@ -6,8 +6,8 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template android_acres} /// {@template android_acres}
/// Area positioned on the left side of the board containing the [Spaceship], /// Area positioned on the left side of the board containing the
/// [SpaceshipRamp], [SpaceshipRail], and [AndroidBumper]s. /// [AndroidSpaceship], [SpaceshipRamp], [SpaceshipRail], and [AndroidBumper]s.
/// {@endtemplate} /// {@endtemplate}
class AndroidAcres extends Blueprint { class AndroidAcres extends Blueprint {
/// {@macro android_acres} /// {@macro android_acres}
@ -23,7 +23,7 @@ class AndroidAcres extends Blueprint {
children: [ children: [
ScoringBehavior(points: 20000), ScoringBehavior(points: 20000),
], ],
)..initialPosition = Vector2(-32.6, -9.2), )..initialPosition = Vector2(-32.8, -9.2),
AndroidBumper.cow( AndroidBumper.cow(
children: [ children: [
ScoringBehavior(points: 20), ScoringBehavior(points: 20),
@ -32,7 +32,7 @@ class AndroidAcres extends Blueprint {
], ],
blueprints: [ blueprints: [
SpaceshipRamp(), SpaceshipRamp(),
Spaceship(position: Vector2(-26.5, -28.5)), AndroidSpaceship(position: Vector2(-26.5, -28.5)),
SpaceshipRail(), SpaceshipRail(),
], ],
); );

@ -16,6 +16,7 @@ class BottomGroup extends Component {
_BottomGroupSide(side: BoardSide.right), _BottomGroupSide(side: BoardSide.right),
_BottomGroupSide(side: BoardSide.left), _BottomGroupSide(side: BoardSide.left),
], ],
priority: RenderPriority.bottomGroup,
); );
} }
@ -28,8 +29,7 @@ class _BottomGroupSide extends Component {
/// {@macro bottom_group_side} /// {@macro bottom_group_side}
_BottomGroupSide({ _BottomGroupSide({
required BoardSide side, required BoardSide side,
}) : _side = side, }) : _side = side;
super(priority: RenderPriority.bottomGroup);
final BoardSide _side; final BoardSide _side;

@ -12,4 +12,4 @@ export 'google_word/google_word.dart';
export 'launcher.dart'; export 'launcher.dart';
export 'multipliers/multipliers.dart'; export 'multipliers/multipliers.dart';
export 'scoring_behavior.dart'; export 'scoring_behavior.dart';
export 'sparky_fire_zone.dart'; export 'sparky_scorch.dart';

@ -5,15 +5,13 @@ 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'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template sparky_fire_zone} /// {@template sparky_scorch}
/// Area positioned at the top left of the board where the [Ball] /// Area positioned at the top left of the board containing the
/// can bounce off [SparkyBumper]s. /// [SparkyComputer], [SparkyAnimatronic], and [SparkyBumper]s.
///
/// When a [Ball] hits [SparkyBumper]s, the bumper animates.
/// {@endtemplate} /// {@endtemplate}
class SparkyFireZone extends Blueprint { class SparkyScorch extends Blueprint {
/// {@macro sparky_fire_zone} /// {@macro sparky_scorch}
SparkyFireZone() SparkyScorch()
: super( : super(
components: [ components: [
SparkyBumper.a( SparkyBumper.a(

@ -13,6 +13,7 @@ extension PinballGameAssetsX on PinballGame {
const dinoTheme = DinoTheme(); const dinoTheme = DinoTheme();
return [ return [
images.load(components.Assets.images.boardBackground.keyName),
images.load(components.Assets.images.ball.ball.keyName), images.load(components.Assets.images.ball.ball.keyName),
images.load(components.Assets.images.ball.flameEffect.keyName), images.load(components.Assets.images.ball.flameEffect.keyName),
images.load(components.Assets.images.signpost.inactive.keyName), images.load(components.Assets.images.signpost.inactive.keyName),
@ -50,50 +51,52 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.boundary.bottom.keyName), images.load(components.Assets.images.boundary.bottom.keyName),
images.load(components.Assets.images.boundary.outer.keyName), images.load(components.Assets.images.boundary.outer.keyName),
images.load(components.Assets.images.boundary.outerBottom.keyName), images.load(components.Assets.images.boundary.outerBottom.keyName),
images.load(components.Assets.images.spaceship.saucer.keyName), images.load(components.Assets.images.android.spaceship.saucer.keyName),
images.load(components.Assets.images.spaceship.bridge.keyName), images
images.load(components.Assets.images.spaceship.ramp.boardOpening.keyName), .load(components.Assets.images.android.spaceship.animatronic.keyName),
images.load(components.Assets.images.android.spaceship.lightBeam.keyName),
images.load(components.Assets.images.android.ramp.boardOpening.keyName),
images.load( images.load(
components.Assets.images.spaceship.ramp.railingForeground.keyName, components.Assets.images.android.ramp.railingForeground.keyName,
), ),
images.load( images.load(
components.Assets.images.spaceship.ramp.railingBackground.keyName, components.Assets.images.android.ramp.railingBackground.keyName,
), ),
images.load(components.Assets.images.spaceship.ramp.main.keyName), images.load(components.Assets.images.android.ramp.main.keyName),
images images.load(components.Assets.images.android.ramp.arrow.inactive.keyName),
.load(components.Assets.images.spaceship.ramp.arrow.inactive.keyName),
images.load( images.load(
components.Assets.images.spaceship.ramp.arrow.active1.keyName, components.Assets.images.android.ramp.arrow.active1.keyName,
), ),
images.load( images.load(
components.Assets.images.spaceship.ramp.arrow.active2.keyName, components.Assets.images.android.ramp.arrow.active2.keyName,
), ),
images.load( images.load(
components.Assets.images.spaceship.ramp.arrow.active3.keyName, components.Assets.images.android.ramp.arrow.active3.keyName,
), ),
images.load( images.load(
components.Assets.images.spaceship.ramp.arrow.active4.keyName, components.Assets.images.android.ramp.arrow.active4.keyName,
), ),
images.load( images.load(
components.Assets.images.spaceship.ramp.arrow.active5.keyName, components.Assets.images.android.ramp.arrow.active5.keyName,
), ),
images.load(components.Assets.images.spaceship.rail.main.keyName), images.load(components.Assets.images.android.rail.main.keyName),
images.load(components.Assets.images.spaceship.rail.exit.keyName), images.load(components.Assets.images.android.rail.exit.keyName),
images.load(components.Assets.images.androidBumper.a.lit.keyName), images.load(components.Assets.images.android.bumper.a.lit.keyName),
images.load(components.Assets.images.androidBumper.a.dimmed.keyName), images.load(components.Assets.images.android.bumper.a.dimmed.keyName),
images.load(components.Assets.images.androidBumper.b.lit.keyName), images.load(components.Assets.images.android.bumper.b.lit.keyName),
images.load(components.Assets.images.androidBumper.b.dimmed.keyName), images.load(components.Assets.images.android.bumper.b.dimmed.keyName),
images.load(components.Assets.images.androidBumper.cow.lit.keyName), images.load(components.Assets.images.android.bumper.cow.lit.keyName),
images.load(components.Assets.images.androidBumper.cow.dimmed.keyName), images.load(components.Assets.images.android.bumper.cow.dimmed.keyName),
images.load(components.Assets.images.sparky.computer.top.keyName), images.load(components.Assets.images.sparky.computer.top.keyName),
images.load(components.Assets.images.sparky.computer.base.keyName), images.load(components.Assets.images.sparky.computer.base.keyName),
images.load(components.Assets.images.sparky.computer.glow.keyName),
images.load(components.Assets.images.sparky.animatronic.keyName), images.load(components.Assets.images.sparky.animatronic.keyName),
images.load(components.Assets.images.sparky.bumper.a.inactive.keyName), images.load(components.Assets.images.sparky.bumper.a.lit.keyName),
images.load(components.Assets.images.sparky.bumper.a.active.keyName), images.load(components.Assets.images.sparky.bumper.a.dimmed.keyName),
images.load(components.Assets.images.sparky.bumper.b.active.keyName), images.load(components.Assets.images.sparky.bumper.b.lit.keyName),
images.load(components.Assets.images.sparky.bumper.b.inactive.keyName), images.load(components.Assets.images.sparky.bumper.b.dimmed.keyName),
images.load(components.Assets.images.sparky.bumper.c.active.keyName), images.load(components.Assets.images.sparky.bumper.c.lit.keyName),
images.load(components.Assets.images.sparky.bumper.c.inactive.keyName), images.load(components.Assets.images.sparky.bumper.c.dimmed.keyName),
images.load(components.Assets.images.backboard.backboardScores.keyName), images.load(components.Assets.images.backboard.backboardScores.keyName),
images.load(components.Assets.images.backboard.backboardGameOver.keyName), images.load(components.Assets.images.backboard.backboardGameOver.keyName),
images.load(components.Assets.images.googleWord.letter1.keyName), images.load(components.Assets.images.googleWord.letter1.keyName),

@ -9,11 +9,10 @@ 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:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball/gen/assets.gen.dart';
import 'package:pinball_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets; 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' hide Assets; import 'package:pinball_theme/pinball_theme.dart';
class PinballGame extends Forge2DGame class PinballGame extends Forge2DGame
with with
@ -46,16 +45,16 @@ class PinballGame extends Forge2DGame
unawaited(add(gameFlowController = GameFlowController(this))); unawaited(add(gameFlowController = GameFlowController(this)));
unawaited(add(CameraController(this))); unawaited(add(CameraController(this)));
unawaited(add(Backboard.waiting(position: Vector2(0, -88)))); unawaited(add(Backboard.waiting(position: Vector2(0, -88))));
await add(BoardBackgroundSpriteComponent());
await add(Drain()); await add(Drain());
await add(BottomGroup()); await add(BottomGroup());
unawaited(addFromBlueprint(Boundaries())); unawaited(addFromBlueprint(Boundaries()));
unawaited(addFromBlueprint(LaunchRamp()));
final launcher = Launcher(); final launcher = Launcher();
unawaited(addFromBlueprint(launcher)); unawaited(addFromBlueprint(launcher));
await add(Multipliers()); await add(Multipliers());
await add(FlutterForest()); await add(FlutterForest());
await addFromBlueprint(SparkyFireZone()); await addFromBlueprint(SparkyScorch());
await addFromBlueprint(AndroidAcres()); await addFromBlueprint(AndroidAcres());
await addFromBlueprint(DinoDesert()); await addFromBlueprint(DinoDesert());
unawaited(addFromBlueprint(Slingshots())); unawaited(addFromBlueprint(Slingshots()));
@ -68,7 +67,7 @@ class PinballGame extends Forge2DGame
), ),
); );
controller.attachTo(launcher.components.whereType<Plunger>().first); controller.attachTo(launcher.components.whereType<Plunger>().single);
await super.onLoad(); await super.onLoad();
} }
@ -186,26 +185,25 @@ class DebugPinballGame extends PinballGame with FPSCounter {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
await _loadBackground();
await add(_DebugInformation()); await add(_DebugInformation());
} }
// TODO(alestiago): Move to PinballGame once we have the real background // TODO(allisonryan0002): Remove after google letters have been correctly
// component. // placed.
Future<void> _loadBackground() async { // Future<void> _loadBackground() async {
final sprite = await loadSprite( // final sprite = await loadSprite(
Assets.images.components.background.path, // Assets.images.components.background.path,
); // );
final spriteComponent = SpriteComponent( // final spriteComponent = SpriteComponent(
sprite: sprite, // sprite: sprite,
size: Vector2(120, 160), // size: Vector2(120, 160),
anchor: Anchor.center, // anchor: Anchor.center,
) // )
..position = Vector2(0, -7.8) // ..position = Vector2(0, -7.8)
..priority = RenderPriority.background; // ..priority = RenderPriority.boardBackground;
await add(spriteComponent); // await add(spriteComponent);
} // }
@override @override
void onTapUp(TapUpInfo info) { void onTapUp(TapUpInfo info) {

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball/gen/gen.dart'; import 'package:pinball/gen/gen.dart';
import 'package:pinball/theme/app_colors.dart'; import 'package:pinball_ui/pinball_ui.dart';
/// {@template game_hud} /// {@template game_hud}
/// Overlay on the [PinballGame]. /// Overlay on the [PinballGame].
@ -72,7 +72,7 @@ class _ScoreViewDecoration extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: radius, borderRadius: radius,
border: Border.all( border: Border.all(
color: AppColors.white, color: PinballColors.white,
width: borderWidth, width: borderWidth,
), ),
image: DecorationImage( image: DecorationImage(

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.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';
import 'package:pinball/theme/theme.dart'; import 'package:pinball_ui/pinball_ui.dart';
/// {@template round_count_display} /// {@template round_count_display}
/// Colored square indicating if a round is available. /// Colored square indicating if a round is available.
@ -20,9 +20,7 @@ class RoundCountDisplay extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.rounds, l10n.rounds,
style: AppTextStyle.subtitle1.copyWith( style: Theme.of(context).textTheme.subtitle1,
color: AppColors.yellow,
),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
Row( Row(
@ -53,9 +51,9 @@ class RoundIndicator extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final color = isActive ? AppColors.yellow : AppColors.yellow.withAlpha(128); final color =
isActive ? PinballColors.yellow : PinballColors.yellow.withAlpha(128);
const size = 8.0; const size = 8.0;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Container( child: Container(

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.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';
import 'package:pinball/theme/theme.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template score_view} /// {@template score_view}
@ -38,9 +37,7 @@ class _GameOver extends StatelessWidget {
return Text( return Text(
l10n.gameOver, l10n.gameOver,
style: AppTextStyle.headline1.copyWith( style: Theme.of(context).textTheme.headline1,
color: AppColors.white,
),
); );
} }
} }
@ -58,9 +55,7 @@ class _ScoreDisplay extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.score.toLowerCase(), l10n.score.toLowerCase(),
style: AppTextStyle.subtitle1.copyWith( style: Theme.of(context).textTheme.subtitle1,
color: AppColors.yellow,
),
), ),
const _ScoreText(), const _ScoreText(),
const RoundCountDisplay(), const RoundCountDisplay(),
@ -78,9 +73,7 @@ class _ScoreText extends StatelessWidget {
return Text( return Text(
score.formatScore(), score.formatScore(),
style: AppTextStyle.headline1.copyWith( style: Theme.of(context).textTheme.headline1,
color: AppColors.white,
),
); );
} }
} }

@ -107,5 +107,21 @@
"rounds": "Ball Ct:", "rounds": "Ball Ct:",
"@rounds": { "@rounds": {
"description": "Text displayed on the scoreboard widget to indicate rounds left" "description": "Text displayed on the scoreboard widget to indicate rounds left"
},
"footerMadeWithText": "Made with ",
"@footerMadeWithText": {
"description": "Text shown on the footer which mentions technologies used to build the app."
},
"footerFlutterLinkText": "Flutter",
"@footerFlutterLinkText": {
"description": "Text on the link shown on the footer which navigates to the Flutter page"
},
"footerFirebaseLinkText": "Firebase",
"@footerFirebaseLinkText": {
"description": "Text on the link shown on the footer which navigates to the Firebase page"
},
"footerGoogleIOText": "Google I/O",
"@footerGoogleIOText": {
"description": "Text shown on the footer which mentions Google I/O"
} }
} }

@ -1,15 +0,0 @@
{
"@@locale": "es",
"play": "Jugar",
"@play": {
"description": "Text displayed on the landing page play button"
},
"start": "Comienzo",
"@start": {
"description": "Text displayed on the character selection page start button"
},
"characterSelectionTitle": "¡Elige a tu personaje!",
"@characterSelectionTitle": {
"description": "Title text displayed on the character selection page"
}
}

@ -5,16 +5,27 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT. // https://opensource.org/licenses/MIT.
import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart';
import 'package:firebase_core/firebase_core.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_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
void main() { void main() {
bootstrap((firestore) async { bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore); final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio(); final pinballAudio = PinballAudio();
unawaited(
Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(),
),
);
return App( return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballAudio: pinballAudio,
); );

@ -5,16 +5,27 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT. // https://opensource.org/licenses/MIT.
import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart';
import 'package:firebase_core/firebase_core.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_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
void main() { void main() {
bootstrap((firestore) async { bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore); final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio(); final pinballAudio = PinballAudio();
unawaited(
Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(),
),
);
return App( return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballAudio: pinballAudio,
); );

@ -5,16 +5,27 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT. // https://opensource.org/licenses/MIT.
import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart';
import 'package:firebase_core/firebase_core.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_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
void main() { void main() {
bootstrap((firestore) async { bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore); final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio(); final pinballAudio = PinballAudio();
unawaited(
Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(),
),
);
return App( return App(
authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballAudio: pinballAudio,
); );

@ -5,7 +5,6 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/gen/gen.dart'; import 'package:pinball/gen/gen.dart';
import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/l10n/l10n.dart';
import 'package:pinball/theme/theme.dart';
import 'package:pinball_ui/pinball_ui.dart'; import 'package:pinball_ui/pinball_ui.dart';
import 'package:platform_helper/platform_helper.dart'; import 'package:platform_helper/platform_helper.dart';
@ -122,7 +121,7 @@ class _MobileLaunchControls extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = context.l10n; final l10n = context.l10n;
const textStyle = AppTextStyle.subtitle3; final textStyle = Theme.of(context).textTheme.headline3;
return Column( return Column(
children: [ children: [
Text( Text(
@ -138,9 +137,7 @@ class _MobileLaunchControls extends StatelessWidget {
), ),
TextSpan( TextSpan(
text: l10n.launch, text: l10n.launch,
style: textStyle.copyWith( style: textStyle?.copyWith(color: PinballColors.blue),
color: AppColors.blue,
),
), ),
], ],
), ),
@ -156,7 +153,7 @@ class _MobileFlipperControls extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = context.l10n; final l10n = context.l10n;
const textStyle = AppTextStyle.subtitle3; final textStyle = Theme.of(context).textTheme.headline3;
return Column( return Column(
children: [ children: [
Text( Text(
@ -172,9 +169,7 @@ class _MobileFlipperControls extends StatelessWidget {
), ),
TextSpan( TextSpan(
text: l10n.flip, text: l10n.flip,
style: textStyle.copyWith( style: textStyle?.copyWith(color: PinballColors.orange),
color: AppColors.orange,
),
), ),
], ],
), ),
@ -207,21 +202,22 @@ class _HowToPlayHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final l10n = context.l10n; final l10n = context.l10n;
const headerTextStyle = AppTextStyle.title; final textStyle = Theme.of(context).textTheme.headline3?.copyWith(
color: PinballColors.darkBlue,
);
return FittedBox( return FittedBox(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
l10n.howToPlay, l10n.howToPlay,
style: headerTextStyle.copyWith( style: textStyle?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text( Text(
l10n.tipsForFlips, l10n.tipsForFlips,
style: headerTextStyle, style: textStyle,
), ),
], ],
), ),
@ -241,7 +237,7 @@ class _DesktopLaunchControls extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.launchControls, l10n.launchControls,
style: AppTextStyle.headline4, style: Theme.of(context).textTheme.headline4,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Wrap( Wrap(
@ -270,7 +266,7 @@ class _DesktopFlipperControls extends StatelessWidget {
children: [ children: [
Text( Text(
l10n.flipperControls, l10n.flipperControls,
style: AppTextStyle.subtitle2, style: Theme.of(context).textTheme.subtitle2,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Column( Column(
@ -311,8 +307,9 @@ class KeyButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final textStyle = final textStyle =
_control.isArrow ? AppTextStyle.headline1 : AppTextStyle.headline3; _control.isArrow ? textTheme.headline1 : textTheme.headline3;
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(
@ -334,7 +331,7 @@ class KeyButton extends StatelessWidget {
quarterTurns: _control.isDown ? 1 : 0, quarterTurns: _control.isDown ? 1 : 0,
child: Text( child: Text(
_control.getCharacter(context), _control.getCharacter(context),
style: textStyle.copyWith(color: AppColors.white), style: textStyle?.copyWith(color: PinballColors.white),
), ),
), ),
), ),

@ -1,2 +0,0 @@
export 'app_colors.dart';
export 'app_text_style.dart';

@ -0,0 +1,39 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# VSCode related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json

@ -0,0 +1,11 @@
# authentication_repository
[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link]
[![License: MIT][license_badge]][license_link]
Repository to manage user authentication.
[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg
[license_link]: https://opensource.org/licenses/MIT
[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg
[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis

@ -0,0 +1 @@
include: package:very_good_analysis/analysis_options.2.4.0.yaml

@ -0,0 +1,3 @@
library authentication_repository;
export 'src/authentication_repository.dart';

@ -0,0 +1,36 @@
import 'package:firebase_auth/firebase_auth.dart';
/// {@template authentication_exception}
/// Exception for authentication repository failures.
/// {@endtemplate}
class AuthenticationException implements Exception {
/// {@macro authentication_exception}
const AuthenticationException(this.error, this.stackTrace);
/// The error that was caught.
final Object error;
/// The Stacktrace associated with the [error].
final StackTrace stackTrace;
}
/// {@template authentication_repository}
/// Repository to manage user authentication.
/// {@endtemplate}
class AuthenticationRepository {
/// {@macro authentication_repository}
AuthenticationRepository(this._firebaseAuth);
final FirebaseAuth _firebaseAuth;
/// Sign in the existing user anonymously using [FirebaseAuth]. If the
/// authentication process can't be completed, it will throw an
/// [AuthenticationException].
Future<void> authenticateAnonymously() async {
try {
await _firebaseAuth.signInAnonymously();
} on Exception catch (error, stackTrace) {
throw AuthenticationException(error, stackTrace);
}
}
}

@ -0,0 +1,18 @@
name: authentication_repository
description: Repository to manage user authentication.
version: 1.0.0+1
publish_to: none
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
firebase_auth: ^3.3.16
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
mocktail: ^0.2.0
very_good_analysis: ^2.4.0

@ -0,0 +1,40 @@
import 'package:authentication_repository/authentication_repository.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
class MockFirebaseAuth extends Mock implements FirebaseAuth {}
class MockUserCredential extends Mock implements UserCredential {}
void main() {
late FirebaseAuth firebaseAuth;
late UserCredential userCredential;
late AuthenticationRepository authenticationRepository;
group('AuthenticationRepository', () {
setUp(() {
firebaseAuth = MockFirebaseAuth();
userCredential = MockUserCredential();
authenticationRepository = AuthenticationRepository(firebaseAuth);
});
group('authenticateAnonymously', () {
test('completes if no exception is thrown', () async {
when(() => firebaseAuth.signInAnonymously())
.thenAnswer((_) async => userCredential);
await authenticationRepository.authenticateAnonymously();
verify(() => firebaseAuth.signInAnonymously()).called(1);
});
test('throws AuthenticationException when firebase auth fails', () async {
when(() => firebaseAuth.signInAnonymously())
.thenThrow(Exception('oops'));
expect(
() => authenticationRepository.authenticateAnonymously(),
throwsA(isA<AuthenticationException>()),
);
});
});
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

@ -10,11 +10,14 @@ import 'package:flutter/widgets.dart';
class $AssetsImagesGen { class $AssetsImagesGen {
const $AssetsImagesGen(); const $AssetsImagesGen();
$AssetsImagesAndroidBumperGen get androidBumper => $AssetsImagesAndroidGen get android => const $AssetsImagesAndroidGen();
const $AssetsImagesAndroidBumperGen();
$AssetsImagesBackboardGen get backboard => const $AssetsImagesBackboardGen(); $AssetsImagesBackboardGen get backboard => const $AssetsImagesBackboardGen();
$AssetsImagesBallGen get ball => const $AssetsImagesBallGen(); $AssetsImagesBallGen get ball => const $AssetsImagesBallGen();
$AssetsImagesBaseboardGen get baseboard => const $AssetsImagesBaseboardGen(); $AssetsImagesBaseboardGen get baseboard => const $AssetsImagesBaseboardGen();
/// File path: assets/images/board-background.png
AssetGenImage get boardBackground =>
const AssetGenImage('assets/images/board-background.png');
$AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen(); $AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen();
$AssetsImagesDashGen get dash => const $AssetsImagesDashGen(); $AssetsImagesDashGen get dash => const $AssetsImagesDashGen();
$AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen(); $AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen();
@ -29,19 +32,18 @@ class $AssetsImagesGen {
$AssetsImagesPlungerGen get plunger => const $AssetsImagesPlungerGen(); $AssetsImagesPlungerGen get plunger => const $AssetsImagesPlungerGen();
$AssetsImagesSignpostGen get signpost => const $AssetsImagesSignpostGen(); $AssetsImagesSignpostGen get signpost => const $AssetsImagesSignpostGen();
$AssetsImagesSlingshotGen get slingshot => const $AssetsImagesSlingshotGen(); $AssetsImagesSlingshotGen get slingshot => const $AssetsImagesSlingshotGen();
$AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen();
$AssetsImagesSparkyGen get sparky => const $AssetsImagesSparkyGen(); $AssetsImagesSparkyGen get sparky => const $AssetsImagesSparkyGen();
} }
class $AssetsImagesAndroidBumperGen { class $AssetsImagesAndroidGen {
const $AssetsImagesAndroidBumperGen(); const $AssetsImagesAndroidGen();
$AssetsImagesAndroidBumperAGen get a => $AssetsImagesAndroidBumperGen get bumper =>
const $AssetsImagesAndroidBumperAGen(); const $AssetsImagesAndroidBumperGen();
$AssetsImagesAndroidBumperBGen get b => $AssetsImagesAndroidRailGen get rail => const $AssetsImagesAndroidRailGen();
const $AssetsImagesAndroidBumperBGen(); $AssetsImagesAndroidRampGen get ramp => const $AssetsImagesAndroidRampGen();
$AssetsImagesAndroidBumperCowGen get cow => $AssetsImagesAndroidSpaceshipGen get spaceship =>
const $AssetsImagesAndroidBumperCowGen(); const $AssetsImagesAndroidSpaceshipGen();
} }
class $AssetsImagesBackboardGen { class $AssetsImagesBackboardGen {
@ -246,23 +248,6 @@ class $AssetsImagesSlingshotGen {
const AssetGenImage('assets/images/slingshot/upper.png'); const AssetGenImage('assets/images/slingshot/upper.png');
} }
class $AssetsImagesSpaceshipGen {
const $AssetsImagesSpaceshipGen();
/// File path: assets/images/spaceship/bridge.png
AssetGenImage get bridge =>
const AssetGenImage('assets/images/spaceship/bridge.png');
$AssetsImagesSpaceshipRailGen get rail =>
const $AssetsImagesSpaceshipRailGen();
$AssetsImagesSpaceshipRampGen get ramp =>
const $AssetsImagesSpaceshipRampGen();
/// File path: assets/images/spaceship/saucer.png
AssetGenImage get saucer =>
const AssetGenImage('assets/images/spaceship/saucer.png');
}
class $AssetsImagesSparkyGen { class $AssetsImagesSparkyGen {
const $AssetsImagesSparkyGen(); const $AssetsImagesSparkyGen();
@ -276,40 +261,66 @@ class $AssetsImagesSparkyGen {
const $AssetsImagesSparkyComputerGen(); const $AssetsImagesSparkyComputerGen();
} }
class $AssetsImagesAndroidBumperAGen { class $AssetsImagesAndroidBumperGen {
const $AssetsImagesAndroidBumperGen();
$AssetsImagesAndroidBumperAGen get a =>
const $AssetsImagesAndroidBumperAGen(); const $AssetsImagesAndroidBumperAGen();
$AssetsImagesAndroidBumperBGen get b =>
const $AssetsImagesAndroidBumperBGen();
$AssetsImagesAndroidBumperCowGen get cow =>
const $AssetsImagesAndroidBumperCowGen();
}
/// File path: assets/images/android_bumper/a/dimmed.png class $AssetsImagesAndroidRailGen {
AssetGenImage get dimmed => const $AssetsImagesAndroidRailGen();
const AssetGenImage('assets/images/android_bumper/a/dimmed.png');
/// File path: assets/images/android_bumper/a/lit.png /// File path: assets/images/android/rail/exit.png
AssetGenImage get lit => AssetGenImage get exit =>
const AssetGenImage('assets/images/android_bumper/a/lit.png'); const AssetGenImage('assets/images/android/rail/exit.png');
/// File path: assets/images/android/rail/main.png
AssetGenImage get main =>
const AssetGenImage('assets/images/android/rail/main.png');
} }
class $AssetsImagesAndroidBumperBGen { class $AssetsImagesAndroidRampGen {
const $AssetsImagesAndroidBumperBGen(); const $AssetsImagesAndroidRampGen();
/// File path: assets/images/android_bumper/b/dimmed.png $AssetsImagesAndroidRampArrowGen get arrow =>
AssetGenImage get dimmed => const $AssetsImagesAndroidRampArrowGen();
const AssetGenImage('assets/images/android_bumper/b/dimmed.png');
/// File path: assets/images/android_bumper/b/lit.png /// File path: assets/images/android/ramp/board-opening.png
AssetGenImage get lit => AssetGenImage get boardOpening =>
const AssetGenImage('assets/images/android_bumper/b/lit.png'); const AssetGenImage('assets/images/android/ramp/board-opening.png');
/// File path: assets/images/android/ramp/main.png
AssetGenImage get main =>
const AssetGenImage('assets/images/android/ramp/main.png');
/// File path: assets/images/android/ramp/railing-background.png
AssetGenImage get railingBackground =>
const AssetGenImage('assets/images/android/ramp/railing-background.png');
/// File path: assets/images/android/ramp/railing-foreground.png
AssetGenImage get railingForeground =>
const AssetGenImage('assets/images/android/ramp/railing-foreground.png');
} }
class $AssetsImagesAndroidBumperCowGen { class $AssetsImagesAndroidSpaceshipGen {
const $AssetsImagesAndroidBumperCowGen(); const $AssetsImagesAndroidSpaceshipGen();
/// File path: assets/images/android_bumper/cow/dimmed.png /// File path: assets/images/android/spaceship/animatronic.png
AssetGenImage get dimmed => AssetGenImage get animatronic =>
const AssetGenImage('assets/images/android_bumper/cow/dimmed.png'); const AssetGenImage('assets/images/android/spaceship/animatronic.png');
/// File path: assets/images/android_bumper/cow/lit.png /// File path: assets/images/android/spaceship/light-beam.png
AssetGenImage get lit => AssetGenImage get lightBeam =>
const AssetGenImage('assets/images/android_bumper/cow/lit.png'); const AssetGenImage('assets/images/android/spaceship/light-beam.png');
/// File path: assets/images/android/spaceship/saucer.png
AssetGenImage get saucer =>
const AssetGenImage('assets/images/android/spaceship/saucer.png');
} }
class $AssetsImagesDashBumperGen { class $AssetsImagesDashBumperGen {
@ -393,41 +404,6 @@ class $AssetsImagesMultiplierX6Gen {
const AssetGenImage('assets/images/multiplier/x6/lit.png'); const AssetGenImage('assets/images/multiplier/x6/lit.png');
} }
class $AssetsImagesSpaceshipRailGen {
const $AssetsImagesSpaceshipRailGen();
/// File path: assets/images/spaceship/rail/exit.png
AssetGenImage get exit =>
const AssetGenImage('assets/images/spaceship/rail/exit.png');
/// File path: assets/images/spaceship/rail/main.png
AssetGenImage get main =>
const AssetGenImage('assets/images/spaceship/rail/main.png');
}
class $AssetsImagesSpaceshipRampGen {
const $AssetsImagesSpaceshipRampGen();
$AssetsImagesSpaceshipRampArrowGen get arrow =>
const $AssetsImagesSpaceshipRampArrowGen();
/// File path: assets/images/spaceship/ramp/board-opening.png
AssetGenImage get boardOpening =>
const AssetGenImage('assets/images/spaceship/ramp/board-opening.png');
/// File path: assets/images/spaceship/ramp/main.png
AssetGenImage get main =>
const AssetGenImage('assets/images/spaceship/ramp/main.png');
/// File path: assets/images/spaceship/ramp/railing-background.png
AssetGenImage get railingBackground => const AssetGenImage(
'assets/images/spaceship/ramp/railing-background.png');
/// File path: assets/images/spaceship/ramp/railing-foreground.png
AssetGenImage get railingForeground => const AssetGenImage(
'assets/images/spaceship/ramp/railing-foreground.png');
}
class $AssetsImagesSparkyBumperGen { class $AssetsImagesSparkyBumperGen {
const $AssetsImagesSparkyBumperGen(); const $AssetsImagesSparkyBumperGen();
@ -443,11 +419,79 @@ class $AssetsImagesSparkyComputerGen {
AssetGenImage get base => AssetGenImage get base =>
const AssetGenImage('assets/images/sparky/computer/base.png'); const AssetGenImage('assets/images/sparky/computer/base.png');
/// File path: assets/images/sparky/computer/glow.png
AssetGenImage get glow =>
const AssetGenImage('assets/images/sparky/computer/glow.png');
/// File path: assets/images/sparky/computer/top.png /// File path: assets/images/sparky/computer/top.png
AssetGenImage get top => AssetGenImage get top =>
const AssetGenImage('assets/images/sparky/computer/top.png'); const AssetGenImage('assets/images/sparky/computer/top.png');
} }
class $AssetsImagesAndroidBumperAGen {
const $AssetsImagesAndroidBumperAGen();
/// File path: assets/images/android/bumper/a/dimmed.png
AssetGenImage get dimmed =>
const AssetGenImage('assets/images/android/bumper/a/dimmed.png');
/// File path: assets/images/android/bumper/a/lit.png
AssetGenImage get lit =>
const AssetGenImage('assets/images/android/bumper/a/lit.png');
}
class $AssetsImagesAndroidBumperBGen {
const $AssetsImagesAndroidBumperBGen();
/// File path: assets/images/android/bumper/b/dimmed.png
AssetGenImage get dimmed =>
const AssetGenImage('assets/images/android/bumper/b/dimmed.png');
/// File path: assets/images/android/bumper/b/lit.png
AssetGenImage get lit =>
const AssetGenImage('assets/images/android/bumper/b/lit.png');
}
class $AssetsImagesAndroidBumperCowGen {
const $AssetsImagesAndroidBumperCowGen();
/// File path: assets/images/android/bumper/cow/dimmed.png
AssetGenImage get dimmed =>
const AssetGenImage('assets/images/android/bumper/cow/dimmed.png');
/// File path: assets/images/android/bumper/cow/lit.png
AssetGenImage get lit =>
const AssetGenImage('assets/images/android/bumper/cow/lit.png');
}
class $AssetsImagesAndroidRampArrowGen {
const $AssetsImagesAndroidRampArrowGen();
/// File path: assets/images/android/ramp/arrow/active1.png
AssetGenImage get active1 =>
const AssetGenImage('assets/images/android/ramp/arrow/active1.png');
/// File path: assets/images/android/ramp/arrow/active2.png
AssetGenImage get active2 =>
const AssetGenImage('assets/images/android/ramp/arrow/active2.png');
/// File path: assets/images/android/ramp/arrow/active3.png
AssetGenImage get active3 =>
const AssetGenImage('assets/images/android/ramp/arrow/active3.png');
/// File path: assets/images/android/ramp/arrow/active4.png
AssetGenImage get active4 =>
const AssetGenImage('assets/images/android/ramp/arrow/active4.png');
/// File path: assets/images/android/ramp/arrow/active5.png
AssetGenImage get active5 =>
const AssetGenImage('assets/images/android/ramp/arrow/active5.png');
/// File path: assets/images/android/ramp/arrow/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/android/ramp/arrow/inactive.png');
}
class $AssetsImagesDashBumperAGen { class $AssetsImagesDashBumperAGen {
const $AssetsImagesDashBumperAGen(); const $AssetsImagesDashBumperAGen();
@ -484,68 +528,40 @@ class $AssetsImagesDashBumperMainGen {
const AssetGenImage('assets/images/dash/bumper/main/inactive.png'); const AssetGenImage('assets/images/dash/bumper/main/inactive.png');
} }
class $AssetsImagesSpaceshipRampArrowGen {
const $AssetsImagesSpaceshipRampArrowGen();
/// File path: assets/images/spaceship/ramp/arrow/active1.png
AssetGenImage get active1 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active1.png');
/// File path: assets/images/spaceship/ramp/arrow/active2.png
AssetGenImage get active2 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active2.png');
/// File path: assets/images/spaceship/ramp/arrow/active3.png
AssetGenImage get active3 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active3.png');
/// File path: assets/images/spaceship/ramp/arrow/active4.png
AssetGenImage get active4 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active4.png');
/// File path: assets/images/spaceship/ramp/arrow/active5.png
AssetGenImage get active5 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active5.png');
/// File path: assets/images/spaceship/ramp/arrow/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/inactive.png');
}
class $AssetsImagesSparkyBumperAGen { class $AssetsImagesSparkyBumperAGen {
const $AssetsImagesSparkyBumperAGen(); const $AssetsImagesSparkyBumperAGen();
/// File path: assets/images/sparky/bumper/a/active.png /// File path: assets/images/sparky/bumper/a/dimmed.png
AssetGenImage get active => AssetGenImage get dimmed =>
const AssetGenImage('assets/images/sparky/bumper/a/active.png'); const AssetGenImage('assets/images/sparky/bumper/a/dimmed.png');
/// File path: assets/images/sparky/bumper/a/inactive.png /// File path: assets/images/sparky/bumper/a/lit.png
AssetGenImage get inactive => AssetGenImage get lit =>
const AssetGenImage('assets/images/sparky/bumper/a/inactive.png'); const AssetGenImage('assets/images/sparky/bumper/a/lit.png');
} }
class $AssetsImagesSparkyBumperBGen { class $AssetsImagesSparkyBumperBGen {
const $AssetsImagesSparkyBumperBGen(); const $AssetsImagesSparkyBumperBGen();
/// File path: assets/images/sparky/bumper/b/active.png /// File path: assets/images/sparky/bumper/b/dimmed.png
AssetGenImage get active => AssetGenImage get dimmed =>
const AssetGenImage('assets/images/sparky/bumper/b/active.png'); const AssetGenImage('assets/images/sparky/bumper/b/dimmed.png');
/// File path: assets/images/sparky/bumper/b/inactive.png /// File path: assets/images/sparky/bumper/b/lit.png
AssetGenImage get inactive => AssetGenImage get lit =>
const AssetGenImage('assets/images/sparky/bumper/b/inactive.png'); const AssetGenImage('assets/images/sparky/bumper/b/lit.png');
} }
class $AssetsImagesSparkyBumperCGen { class $AssetsImagesSparkyBumperCGen {
const $AssetsImagesSparkyBumperCGen(); const $AssetsImagesSparkyBumperCGen();
/// File path: assets/images/sparky/bumper/c/active.png /// File path: assets/images/sparky/bumper/c/dimmed.png
AssetGenImage get active => AssetGenImage get dimmed =>
const AssetGenImage('assets/images/sparky/bumper/c/active.png'); const AssetGenImage('assets/images/sparky/bumper/c/dimmed.png');
/// File path: assets/images/sparky/bumper/c/inactive.png /// File path: assets/images/sparky/bumper/c/lit.png
AssetGenImage get inactive => AssetGenImage get lit =>
const AssetGenImage('assets/images/sparky/bumper/c/inactive.png'); const AssetGenImage('assets/images/sparky/bumper/c/lit.png');
} }
class Assets { class Assets {

@ -10,7 +10,7 @@ import 'package:pinball_flame/pinball_flame.dart';
export 'cubit/android_bumper_cubit.dart'; export 'cubit/android_bumper_cubit.dart';
/// {@template android_bumper} /// {@template android_bumper}
/// Bumper for area under the [Spaceship]. /// Bumper for area under the [AndroidSpaceship].
/// {@endtemplate} /// {@endtemplate}
class AndroidBumper extends BodyComponent with InitialPosition { class AndroidBumper extends BodyComponent with InitialPosition {
/// {@macro android_bumper} /// {@macro android_bumper}
@ -46,8 +46,8 @@ class AndroidBumper extends BodyComponent with InitialPosition {
}) : this._( }) : this._(
majorRadius: 3.52, majorRadius: 3.52,
minorRadius: 2.97, minorRadius: 2.97,
litAssetPath: Assets.images.androidBumper.a.lit.keyName, litAssetPath: Assets.images.android.bumper.a.lit.keyName,
dimmedAssetPath: Assets.images.androidBumper.a.dimmed.keyName, dimmedAssetPath: Assets.images.android.bumper.a.dimmed.keyName,
spritePosition: Vector2(0, -0.1), spritePosition: Vector2(0, -0.1),
bloc: AndroidBumperCubit(), bloc: AndroidBumperCubit(),
children: children, children: children,
@ -59,8 +59,8 @@ class AndroidBumper extends BodyComponent with InitialPosition {
}) : this._( }) : this._(
majorRadius: 3.19, majorRadius: 3.19,
minorRadius: 2.79, minorRadius: 2.79,
litAssetPath: Assets.images.androidBumper.b.lit.keyName, litAssetPath: Assets.images.android.bumper.b.lit.keyName,
dimmedAssetPath: Assets.images.androidBumper.b.dimmed.keyName, dimmedAssetPath: Assets.images.android.bumper.b.dimmed.keyName,
spritePosition: Vector2(0, -0.1), spritePosition: Vector2(0, -0.1),
bloc: AndroidBumperCubit(), bloc: AndroidBumperCubit(),
children: children, children: children,
@ -72,8 +72,8 @@ class AndroidBumper extends BodyComponent with InitialPosition {
}) : this._( }) : this._(
majorRadius: 3.4, majorRadius: 3.4,
minorRadius: 2.9, minorRadius: 2.9,
litAssetPath: Assets.images.androidBumper.cow.lit.keyName, litAssetPath: Assets.images.android.bumper.cow.lit.keyName,
dimmedAssetPath: Assets.images.androidBumper.cow.dimmed.keyName, dimmedAssetPath: Assets.images.android.bumper.cow.dimmed.keyName,
spritePosition: Vector2(0, -0.68), spritePosition: Vector2(0, -0.68),
bloc: AndroidBumperCubit(), bloc: AndroidBumperCubit(),
children: children, children: children,

@ -0,0 +1,209 @@
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
import 'package:pinball_flame/pinball_flame.dart';
class AndroidSpaceship extends Blueprint {
AndroidSpaceship({required Vector2 position})
: super(
components: [
_SpaceshipSaucer()..initialPosition = position,
_SpaceshipSaucerSpriteAnimationComponent()..position = position,
_LightBeamSpriteComponent()..position = position + Vector2(2.5, 5),
_AndroidHead()..initialPosition = position + Vector2(0.5, 0.25),
_SpaceshipHole(
outsideLayer: Layer.spaceshipExitRail,
outsidePriority: RenderPriority.ballOnSpaceshipRail,
)..initialPosition = position - Vector2(5.3, -5.4),
_SpaceshipHole(
outsideLayer: Layer.board,
outsidePriority: RenderPriority.ballOnBoard,
)..initialPosition = position - Vector2(-7.5, -1.1),
],
);
}
class _SpaceshipSaucer extends BodyComponent with InitialPosition, Layered {
_SpaceshipSaucer() : super(renderBody: false) {
layer = Layer.spaceship;
}
@override
Body createBody() {
final shape = _SpaceshipSaucerShape();
final bodyDef = BodyDef(
position: initialPosition,
userData: this,
angle: -1.7,
);
return world.createBody(bodyDef)..createFixtureFromShape(shape);
}
}
class _SpaceshipSaucerShape extends ChainShape {
_SpaceshipSaucerShape() {
const minorRadius = 9.75;
const majorRadius = 11.9;
createChain(
[
for (var angle = 0.2618; angle <= 6.0214; angle += math.pi / 180)
Vector2(
minorRadius * math.cos(angle),
majorRadius * math.sin(angle),
),
],
);
}
}
class _SpaceshipSaucerSpriteAnimationComponent extends SpriteAnimationComponent
with HasGameRef {
_SpaceshipSaucerSpriteAnimationComponent()
: super(
anchor: Anchor.center,
priority: RenderPriority.spaceshipSaucer,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final spriteSheet = gameRef.images.fromCache(
Assets.images.android.spaceship.saucer.keyName,
);
const amountPerRow = 5;
const amountPerColumn = 3;
final textureSize = Vector2(
spriteSheet.width / amountPerRow,
spriteSheet.height / amountPerColumn,
);
size = textureSize / 10;
animation = SpriteAnimation.fromFrameData(
spriteSheet,
SpriteAnimationData.sequenced(
amount: amountPerRow * amountPerColumn,
amountPerRow: amountPerRow,
stepTime: 1 / 24,
textureSize: textureSize,
),
);
}
}
// TODO(allisonryan0002): add pulsing behavior.
class _LightBeamSpriteComponent extends SpriteComponent with HasGameRef {
_LightBeamSpriteComponent()
: super(
anchor: Anchor.center,
priority: RenderPriority.spaceshipLightBeam,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.android.spaceship.lightBeam.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
}
}
class _AndroidHead extends BodyComponent with InitialPosition, Layered {
_AndroidHead()
: super(
priority: RenderPriority.androidHead,
children: [_AndroidHeadSpriteAnimationComponent()],
renderBody: false,
) {
layer = Layer.spaceship;
}
@override
Body createBody() {
final shape = EllipseShape(
center: Vector2.zero(),
majorRadius: 3.1,
minorRadius: 2,
)..rotate(1.4);
// TODO(allisonryan0002): use bumping behavior.
final fixtureDef = FixtureDef(
shape,
restitution: 0.1,
);
final bodyDef = BodyDef(position: initialPosition);
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class _AndroidHeadSpriteAnimationComponent extends SpriteAnimationComponent
with HasGameRef {
_AndroidHeadSpriteAnimationComponent()
: super(
anchor: Anchor.center,
position: Vector2(-0.24, -2.6),
);
@override
Future<void> onLoad() async {
await super.onLoad();
final spriteSheet = gameRef.images.fromCache(
Assets.images.android.spaceship.animatronic.keyName,
);
const amountPerRow = 18;
const amountPerColumn = 4;
final textureSize = Vector2(
spriteSheet.width / amountPerRow,
spriteSheet.height / amountPerColumn,
);
size = textureSize / 10;
animation = SpriteAnimation.fromFrameData(
spriteSheet,
SpriteAnimationData.sequenced(
amount: amountPerRow * amountPerColumn,
amountPerRow: amountPerRow,
stepTime: 1 / 24,
textureSize: textureSize,
),
);
}
}
class _SpaceshipHole extends LayerSensor {
_SpaceshipHole({required Layer outsideLayer, required int outsidePriority})
: super(
insideLayer: Layer.spaceship,
outsideLayer: outsideLayer,
orientation: LayerEntranceOrientation.down,
insidePriority: RenderPriority.ballOnSpaceship,
outsidePriority: outsidePriority,
) {
layer = Layer.spaceship;
}
@override
Shape get shape {
return ArcShape(
center: Vector2(0, -3.2),
arcRadius: 5,
angle: 1,
rotation: -2,
);
}
}

@ -115,7 +115,7 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
math.pow(defaultGravity, 2) - math.pow(positionalXForce, 2), math.pow(defaultGravity, 2) - math.pow(positionalXForce, 2),
); );
body.gravityOverride = Vector2(positionalXForce, positionalYForce); body.gravityOverride = Vector2(-positionalXForce, positionalYForce);
} }
} }

@ -0,0 +1,26 @@
// ignore_for_file: public_member_api_docs
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
class BoardBackgroundSpriteComponent extends SpriteComponent with HasGameRef {
BoardBackgroundSpriteComponent()
: super(
anchor: Anchor.center,
priority: RenderPriority.boardBackground,
position: Vector2(0, -1),
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.boardBackground.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
}
}

@ -1,7 +1,9 @@
export 'android_bumper/android_bumper.dart'; export 'android_bumper/android_bumper.dart';
export 'android_spaceship.dart';
export 'backboard/backboard.dart'; export 'backboard/backboard.dart';
export 'ball.dart'; export 'ball.dart';
export 'baseboard.dart'; export 'baseboard.dart';
export 'board_background_sprite_component.dart';
export 'board_dimensions.dart'; export 'board_dimensions.dart';
export 'board_side.dart'; export 'board_side.dart';
export 'boundaries.dart'; export 'boundaries.dart';
@ -27,7 +29,6 @@ export 'score_text.dart';
export 'shapes/shapes.dart'; export 'shapes/shapes.dart';
export 'signpost.dart'; export 'signpost.dart';
export 'slingshot.dart'; export 'slingshot.dart';
export 'spaceship.dart';
export 'spaceship_rail.dart'; export 'spaceship_rail.dart';
export 'spaceship_ramp.dart'; export 'spaceship_ramp.dart';
export 'sparky_animatronic.dart'; export 'sparky_animatronic.dart';

@ -20,7 +20,7 @@ abstract class RenderPriority {
static const int ballOnSpaceshipRamp = static const int ballOnSpaceshipRamp =
_above + spaceshipRampBackgroundRailing; _above + spaceshipRampBackgroundRailing;
/// Render priority for the [Ball] while it's on the [Spaceship]. /// Render priority for the [Ball] while it's on the [AndroidSpaceship].
static const int ballOnSpaceship = _above + spaceshipSaucer; static const int ballOnSpaceship = _above + spaceshipSaucer;
/// Render priority for the [Ball] while it's on the [SpaceshipRail]. /// Render priority for the [Ball] while it's on the [SpaceshipRail].
@ -33,13 +33,13 @@ abstract class RenderPriority {
// TODO(allisonryan0002): fix this magic priority. Could bump all priorities // TODO(allisonryan0002): fix this magic priority. Could bump all priorities
// so there are no negatives. // so there are no negatives.
static const int background = 3 * _below + _base; static const int boardBackground = 3 * _below + _base;
// Boundaries // Boundaries
static const int bottomBoundary = _above + dinoBottomWall; static const int bottomBoundary = _above + dinoBottomWall;
static const int outerBoundary = _above + background; static const int outerBoundary = _above + boardBackground;
static const int outerBottomBoundary = _above + rocket; static const int outerBottomBoundary = _above + rocket;
@ -57,7 +57,7 @@ abstract class RenderPriority {
static const int rocket = _below + bottomBoundary; static const int rocket = _below + bottomBoundary;
// Dino Land // Dino Desert
static const int dinoTopWall = _above + ballOnBoard; static const int dinoTopWall = _above + ballOnBoard;
@ -71,12 +71,14 @@ abstract class RenderPriority {
static const int flutterForest = _above + launchRampForegroundRailing; static const int flutterForest = _above + launchRampForegroundRailing;
// Sparky Fire Zone // Sparky Scorch
static const int computerBase = _below + ballOnBoard; static const int computerBase = _below + ballOnBoard;
static const int computerTop = _above + ballOnBoard; static const int computerTop = _above + ballOnBoard;
static const int computerGlow = _above + ballOnBoard;
static const int sparkyAnimatronic = _above + spaceshipRampForegroundRailing; static const int sparkyAnimatronic = _above + spaceshipRampForegroundRailing;
static const int sparkyBumper = _above + ballOnBoard; static const int sparkyBumper = _above + ballOnBoard;
@ -91,7 +93,7 @@ abstract class RenderPriority {
static const int spaceshipSaucer = _above + ballOnSpaceshipRail; static const int spaceshipSaucer = _above + ballOnSpaceshipRail;
static const int spaceshipSaucerWall = _above + spaceshipSaucer; static const int spaceshipLightBeam = _below + spaceshipSaucer;
static const int androidHead = _above + spaceshipSaucer; static const int androidHead = _above + spaceshipSaucer;

@ -1,246 +0,0 @@
import 'dart:async';
import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
import 'package:pinball_flame/pinball_flame.dart';
/// {@template spaceship}
/// A [Blueprint] which creates the spaceship feature.
/// {@endtemplate}
class Spaceship extends Blueprint {
/// {@macro spaceship}
Spaceship({required Vector2 position})
: super(
components: [
SpaceshipSaucer()..initialPosition = position,
_SpaceshipEntrance()..initialPosition = position,
AndroidHead()..initialPosition = position,
_SpaceshipHole(
outsideLayer: Layer.spaceshipExitRail,
outsidePriority: RenderPriority.ballOnSpaceshipRail,
)..initialPosition = position - Vector2(5.2, -4.8),
_SpaceshipHole(
outsideLayer: Layer.board,
outsidePriority: RenderPriority.ballOnBoard,
)..initialPosition = position - Vector2(-7.2, -0.8),
SpaceshipWall()..initialPosition = position,
],
);
/// Total size of the spaceship.
static final size = Vector2(25, 19);
}
/// {@template spaceship_saucer}
/// A [BodyComponent] for the base, or the saucer of the spaceship
/// {@endtemplate}
class SpaceshipSaucer extends BodyComponent with InitialPosition, Layered {
/// {@macro spaceship_saucer}
SpaceshipSaucer()
: super(
priority: RenderPriority.spaceshipSaucer,
renderBody: false,
children: [
_SpaceshipSaucerSpriteComponent(),
],
) {
layer = Layer.spaceship;
}
@override
Body createBody() {
final shape = CircleShape()..radius = 3;
final fixtureDef = FixtureDef(
shape,
isSensor: true,
);
final bodyDef = BodyDef(
position: initialPosition,
userData: this,
);
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class _SpaceshipSaucerSpriteComponent extends SpriteComponent with HasGameRef {
_SpaceshipSaucerSpriteComponent()
: super(
anchor: Anchor.center,
// TODO(alestiago): Refactor to use sprite orignial size instead.
size: Spaceship.size,
);
@override
Future<void> onLoad() async {
await super.onLoad();
// TODO(alestiago): Use cached sprite.
sprite = await gameRef.loadSprite(
Assets.images.spaceship.saucer.keyName,
);
}
}
/// {@template spaceship_bridge}
/// A [BodyComponent] that provides both the collision and the rotation
/// animation for the bridge.
/// {@endtemplate}
class AndroidHead extends BodyComponent with InitialPosition, Layered {
/// {@macro spaceship_bridge}
AndroidHead()
: super(
priority: RenderPriority.androidHead,
children: [_AndroidHeadSpriteAnimation()],
renderBody: false,
) {
layer = Layer.spaceship;
}
@override
Body createBody() {
final circleShape = CircleShape()..radius = 2;
final bodyDef = BodyDef(
position: initialPosition,
userData: this,
);
return world.createBody(bodyDef)
..createFixture(
FixtureDef(circleShape)..restitution = 0.4,
);
}
}
class _AndroidHeadSpriteAnimation extends SpriteAnimationComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final image = await gameRef.images.load(
Assets.images.spaceship.bridge.keyName,
);
size = Vector2(8.2, 10);
position = Vector2(0, -2);
anchor = Anchor.center;
final data = SpriteAnimationData.sequenced(
amount: 72,
amountPerRow: 24,
stepTime: 0.05,
textureSize: size * 10,
);
animation = SpriteAnimation.fromFrameData(image, data);
}
}
class _SpaceshipEntrance extends LayerSensor {
_SpaceshipEntrance()
: super(
insideLayer: Layer.spaceship,
orientation: LayerEntranceOrientation.up,
insidePriority: RenderPriority.ballOnSpaceship,
) {
layer = Layer.spaceship;
}
@override
Shape get shape {
final radius = Spaceship.size.y / 2;
return PolygonShape()
..setAsEdge(
Vector2(
radius * cos(20 * pi / 180),
radius * sin(20 * pi / 180),
)..rotate(90 * pi / 180),
Vector2(
radius * cos(340 * pi / 180),
radius * sin(340 * pi / 180),
)..rotate(90 * pi / 180),
);
}
}
class _SpaceshipHole extends LayerSensor {
_SpaceshipHole({required Layer outsideLayer, required int outsidePriority})
: super(
insideLayer: Layer.spaceship,
outsideLayer: outsideLayer,
orientation: LayerEntranceOrientation.down,
insidePriority: RenderPriority.ballOnSpaceship,
outsidePriority: outsidePriority,
) {
layer = Layer.spaceship;
}
@override
Shape get shape {
return ArcShape(
center: Vector2(0, -3.2),
arcRadius: 5,
angle: 1,
rotation: -2,
);
}
}
/// {@template spaceship_wall_shape}
/// The [ChainShape] that defines the shape of the [SpaceshipWall].
/// {@endtemplate}
class _SpaceshipWallShape extends ChainShape {
/// {@macro spaceship_wall_shape}
_SpaceshipWallShape() {
final minorRadius = (Spaceship.size.y - 2) / 2;
final majorRadius = (Spaceship.size.x - 2) / 2;
createChain(
[
// TODO(alestiago): Try converting this logic to radian.
for (var angle = 20; angle <= 340; angle++)
Vector2(
minorRadius * cos(angle * pi / 180),
majorRadius * sin(angle * pi / 180),
),
],
);
}
}
/// {@template spaceship_wall}
/// A [BodyComponent] that provides the collision for the wall
/// surrounding the spaceship.
///
/// It has a small opening to allow the [Ball] to get inside the spaceship
/// saucer.
///
/// It also contains the [SpriteComponent] for the lower wall
/// {@endtemplate}
class SpaceshipWall extends BodyComponent with InitialPosition, Layered {
/// {@macro spaceship_wall}
SpaceshipWall()
: super(
priority: RenderPriority.spaceshipSaucerWall,
renderBody: false,
) {
layer = Layer.spaceship;
}
@override
Body createBody() {
final shape = _SpaceshipWallShape();
final fixtureDef = FixtureDef(shape);
final bodyDef = BodyDef(
position: initialPosition,
userData: this,
angle: -1.7,
);
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}

@ -6,7 +6,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template spaceship_rail} /// {@template spaceship_rail}
/// A [Blueprint] for the rail exiting the [Spaceship]. /// A [Blueprint] for the rail exiting the [AndroidSpaceship].
/// {@endtemplate} /// {@endtemplate}
class SpaceshipRail extends Blueprint { class SpaceshipRail extends Blueprint {
/// {@macro spaceship_rail} /// {@macro spaceship_rail}
@ -116,7 +116,7 @@ class _SpaceshipRailSpriteComponent extends SpriteComponent with HasGameRef {
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.spaceship.rail.main.keyName, Assets.images.android.rail.main.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;
@ -139,7 +139,7 @@ class _SpaceshipRailExitSpriteComponent extends SpriteComponent
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.spaceship.rail.exit.keyName, Assets.images.android.rail.exit.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;

@ -8,7 +8,7 @@ import 'package:pinball_components/pinball_components.dart' hide Assets;
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template spaceship_ramp} /// {@template spaceship_ramp}
/// A [Blueprint] which creates the ramp leading into the [Spaceship]. /// A [Blueprint] which creates the ramp leading into the [AndroidSpaceship].
/// {@endtemplate} /// {@endtemplate}
class SpaceshipRamp extends Blueprint { class SpaceshipRamp extends Blueprint {
/// {@macro spaceship_ramp} /// {@macro spaceship_ramp}
@ -73,17 +73,17 @@ extension on SpaceshipRampArrowSpriteState {
String get path { String get path {
switch (this) { switch (this) {
case SpaceshipRampArrowSpriteState.inactive: case SpaceshipRampArrowSpriteState.inactive:
return Assets.images.spaceship.ramp.arrow.inactive.keyName; return Assets.images.android.ramp.arrow.inactive.keyName;
case SpaceshipRampArrowSpriteState.active1: case SpaceshipRampArrowSpriteState.active1:
return Assets.images.spaceship.ramp.arrow.active1.keyName; return Assets.images.android.ramp.arrow.active1.keyName;
case SpaceshipRampArrowSpriteState.active2: case SpaceshipRampArrowSpriteState.active2:
return Assets.images.spaceship.ramp.arrow.active2.keyName; return Assets.images.android.ramp.arrow.active2.keyName;
case SpaceshipRampArrowSpriteState.active3: case SpaceshipRampArrowSpriteState.active3:
return Assets.images.spaceship.ramp.arrow.active3.keyName; return Assets.images.android.ramp.arrow.active3.keyName;
case SpaceshipRampArrowSpriteState.active4: case SpaceshipRampArrowSpriteState.active4:
return Assets.images.spaceship.ramp.arrow.active4.keyName; return Assets.images.android.ramp.arrow.active4.keyName;
case SpaceshipRampArrowSpriteState.active5: case SpaceshipRampArrowSpriteState.active5:
return Assets.images.spaceship.ramp.arrow.active5.keyName; return Assets.images.android.ramp.arrow.active5.keyName;
} }
} }
@ -161,7 +161,7 @@ class _SpaceshipRampBackgroundRailingSpriteComponent extends SpriteComponent
await super.onLoad(); await super.onLoad();
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.spaceship.ramp.railingBackground.keyName, Assets.images.android.ramp.railingBackground.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;
@ -182,7 +182,7 @@ class _SpaceshipRampBackgroundRampSpriteComponent extends SpriteComponent
await super.onLoad(); await super.onLoad();
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.spaceship.ramp.main.keyName, Assets.images.android.ramp.main.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;
@ -234,7 +234,7 @@ class _SpaceshipRampBoardOpeningSpriteComponent extends SpriteComponent
await super.onLoad(); await super.onLoad();
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.spaceship.ramp.boardOpening.keyName, Assets.images.android.ramp.boardOpening.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;
@ -304,7 +304,7 @@ class _SpaceshipRampForegroundRailingSpriteComponent extends SpriteComponent
await super.onLoad(); await super.onLoad();
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.spaceship.ramp.railingForeground.keyName, Assets.images.android.ramp.railingForeground.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;

@ -3,19 +3,19 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.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.active] when /// Makes a [SparkyBumper] blink back to [SparkyBumperState.lit] when
/// [SparkyBumperState.inactive]. /// [SparkyBumperState.dimmed].
/// {@endtemplate} /// {@endtemplate}
class SparkyBumperBlinkingBehavior extends TimerComponent class SparkyBumperBlinkingBehavior extends TimerComponent
with ParentIsA<SparkyBumper> { with ParentIsA<SparkyBumper> {
/// {@macro sparky_bumper_sprite_behavior} /// {@macro sparky_bumper_blinking_behavior}
SparkyBumperBlinkingBehavior() : super(period: 0.05); SparkyBumperBlinkingBehavior() : super(period: 0.05);
void _onNewState(SparkyBumperState state) { void _onNewState(SparkyBumperState state) {
switch (state) { switch (state) {
case SparkyBumperState.active: case SparkyBumperState.lit:
break; break;
case SparkyBumperState.inactive: case SparkyBumperState.dimmed:
timer timer
..reset() ..reset()
..start(); ..start();

@ -5,13 +5,13 @@ import 'package:bloc/bloc.dart';
part 'sparky_bumper_state.dart'; part 'sparky_bumper_state.dart';
class SparkyBumperCubit extends Cubit<SparkyBumperState> { class SparkyBumperCubit extends Cubit<SparkyBumperState> {
SparkyBumperCubit() : super(SparkyBumperState.active); SparkyBumperCubit() : super(SparkyBumperState.lit);
void onBallContacted() { void onBallContacted() {
emit(SparkyBumperState.inactive); emit(SparkyBumperState.dimmed);
} }
void onBlinked() { void onBlinked() {
emit(SparkyBumperState.active); emit(SparkyBumperState.lit);
} }
} }

@ -1,10 +1,8 @@
// ignore_for_file: public_member_api_docs
part of 'sparky_bumper_cubit.dart'; part of 'sparky_bumper_cubit.dart';
/// Indicates the [SparkyBumperCubit]'s current state.
enum SparkyBumperState { enum SparkyBumperState {
/// A lit up bumper. lit,
active, dimmed,
/// A dimmed bumper.
inactive,
} }

@ -17,8 +17,8 @@ class SparkyBumper extends BodyComponent with InitialPosition {
SparkyBumper._({ SparkyBumper._({
required double majorRadius, required double majorRadius,
required double minorRadius, required double minorRadius,
required String onAssetPath, required String litAssetPath,
required String offAssetPath, required String dimmedAssetPath,
required Vector2 spritePosition, required Vector2 spritePosition,
required this.bloc, required this.bloc,
Iterable<Component>? children, Iterable<Component>? children,
@ -31,8 +31,8 @@ class SparkyBumper extends BodyComponent with InitialPosition {
SparkyBumperBallContactBehavior(), SparkyBumperBallContactBehavior(),
SparkyBumperBlinkingBehavior(), SparkyBumperBlinkingBehavior(),
_SparkyBumperSpriteGroupComponent( _SparkyBumperSpriteGroupComponent(
onAssetPath: onAssetPath, litAssetPath: litAssetPath,
offAssetPath: offAssetPath, dimmedAssetPath: dimmedAssetPath,
position: spritePosition, position: spritePosition,
state: bloc.state, state: bloc.state,
), ),
@ -46,8 +46,8 @@ class SparkyBumper extends BodyComponent with InitialPosition {
}) : this._( }) : this._(
majorRadius: 2.9, majorRadius: 2.9,
minorRadius: 2.1, minorRadius: 2.1,
onAssetPath: Assets.images.sparky.bumper.a.active.keyName, litAssetPath: Assets.images.sparky.bumper.a.lit.keyName,
offAssetPath: Assets.images.sparky.bumper.a.inactive.keyName, dimmedAssetPath: Assets.images.sparky.bumper.a.dimmed.keyName,
spritePosition: Vector2(0, -0.25), spritePosition: Vector2(0, -0.25),
bloc: SparkyBumperCubit(), bloc: SparkyBumperCubit(),
children: children, children: children,
@ -59,8 +59,8 @@ class SparkyBumper extends BodyComponent with InitialPosition {
}) : this._( }) : this._(
majorRadius: 2.85, majorRadius: 2.85,
minorRadius: 2, minorRadius: 2,
onAssetPath: Assets.images.sparky.bumper.b.active.keyName, litAssetPath: Assets.images.sparky.bumper.b.lit.keyName,
offAssetPath: Assets.images.sparky.bumper.b.inactive.keyName, dimmedAssetPath: Assets.images.sparky.bumper.b.dimmed.keyName,
spritePosition: Vector2(0, -0.35), spritePosition: Vector2(0, -0.35),
bloc: SparkyBumperCubit(), bloc: SparkyBumperCubit(),
children: children, children: children,
@ -72,8 +72,8 @@ class SparkyBumper extends BodyComponent with InitialPosition {
}) : this._( }) : this._(
majorRadius: 3, majorRadius: 3,
minorRadius: 2.2, minorRadius: 2.2,
onAssetPath: Assets.images.sparky.bumper.c.active.keyName, litAssetPath: Assets.images.sparky.bumper.c.lit.keyName,
offAssetPath: Assets.images.sparky.bumper.c.inactive.keyName, dimmedAssetPath: Assets.images.sparky.bumper.c.dimmed.keyName,
spritePosition: Vector2(0, -0.4), spritePosition: Vector2(0, -0.4),
bloc: SparkyBumperCubit(), bloc: SparkyBumperCubit(),
children: children, children: children,
@ -127,20 +127,20 @@ class _SparkyBumperSpriteGroupComponent
extends SpriteGroupComponent<SparkyBumperState> extends SpriteGroupComponent<SparkyBumperState>
with HasGameRef, ParentIsA<SparkyBumper> { with HasGameRef, ParentIsA<SparkyBumper> {
_SparkyBumperSpriteGroupComponent({ _SparkyBumperSpriteGroupComponent({
required String onAssetPath, required String litAssetPath,
required String offAssetPath, required String dimmedAssetPath,
required Vector2 position, required Vector2 position,
required SparkyBumperState state, required SparkyBumperState state,
}) : _onAssetPath = onAssetPath, }) : _litAssetPath = litAssetPath,
_offAssetPath = offAssetPath, _dimmedAssetPath = dimmedAssetPath,
super( super(
anchor: Anchor.center, anchor: Anchor.center,
position: position, position: position,
current: state, current: state,
); );
final String _onAssetPath; final String _litAssetPath;
final String _offAssetPath; final String _dimmedAssetPath;
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
@ -151,11 +151,11 @@ class _SparkyBumperSpriteGroupComponent
parent.bloc.stream.listen((state) => current = state); parent.bloc.stream.listen((state) => current = state);
final sprites = { final sprites = {
SparkyBumperState.active: Sprite( SparkyBumperState.lit: Sprite(
gameRef.images.fromCache(_onAssetPath), gameRef.images.fromCache(_litAssetPath),
), ),
SparkyBumperState.inactive: Sprite( SparkyBumperState.dimmed: Sprite(
gameRef.images.fromCache(_offAssetPath), gameRef.images.fromCache(_dimmedAssetPath),
), ),
}; };
this.sprites = sprites; this.sprites = sprites;

@ -15,6 +15,7 @@ class SparkyComputer extends Blueprint {
components: [ components: [
_ComputerBase(), _ComputerBase(),
_ComputerTopSpriteComponent(), _ComputerTopSpriteComponent(),
_ComputerGlowSpriteComponent(),
], ],
); );
} }
@ -65,15 +66,17 @@ class _ComputerBaseSpriteComponent extends SpriteComponent with HasGameRef {
_ComputerBaseSpriteComponent() _ComputerBaseSpriteComponent()
: super( : super(
anchor: Anchor.center, anchor: Anchor.center,
position: Vector2(-11.95, -48.35), position: Vector2(-12.1, -48.15),
); );
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.sparky.computer.base.keyName, Assets.images.sparky.computer.base.keyName,
),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
@ -84,7 +87,7 @@ class _ComputerTopSpriteComponent extends SpriteComponent with HasGameRef {
_ComputerTopSpriteComponent() _ComputerTopSpriteComponent()
: super( : super(
anchor: Anchor.center, anchor: Anchor.center,
position: Vector2(-12.45, -49.75), position: Vector2(-12.52, -49.37),
priority: RenderPriority.computerTop, priority: RenderPriority.computerTop,
); );
@ -92,8 +95,32 @@ class _ComputerTopSpriteComponent extends SpriteComponent with HasGameRef {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.sparky.computer.top.keyName, Assets.images.sparky.computer.top.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
}
}
class _ComputerGlowSpriteComponent extends SpriteComponent with HasGameRef {
_ComputerGlowSpriteComponent()
: super(
anchor: Anchor.center,
position: Vector2(7.4, 10),
priority: RenderPriority.computerGlow,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.sparky.computer.glow.keyName,
),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;

@ -57,16 +57,16 @@ flutter:
- assets/images/dash/bumper/a/ - assets/images/dash/bumper/a/
- assets/images/dash/bumper/b/ - assets/images/dash/bumper/b/
- assets/images/dash/bumper/main/ - assets/images/dash/bumper/main/
- assets/images/spaceship/ - assets/images/android/spaceship/
- assets/images/spaceship/rail/ - assets/images/android/rail/
- assets/images/spaceship/ramp/ - assets/images/android/ramp/
- assets/images/spaceship/ramp/arrow/ - assets/images/android/ramp/arrow/
- assets/images/android/bumper/a/
- assets/images/android/bumper/b/
- assets/images/android/bumper/cow/
- assets/images/kicker/ - assets/images/kicker/
- assets/images/plunger/ - assets/images/plunger/
- assets/images/slingshot/ - assets/images/slingshot/
- assets/images/android_bumper/a/
- assets/images/android_bumper/b/
- assets/images/android_bumper/cow/
- assets/images/sparky/ - assets/images/sparky/
- assets/images/sparky/computer/ - assets/images/sparky/computer/
- assets/images/sparky/bumper/a/ - assets/images/sparky/bumper/a/

@ -19,7 +19,7 @@ void main() {
addBottomGroupStories(dashbook); addBottomGroupStories(dashbook);
addPlungerStories(dashbook); addPlungerStories(dashbook);
addSlingshotStories(dashbook); addSlingshotStories(dashbook);
addSparkyBumperStories(dashbook); addSparkyScorchStories(dashbook);
addAndroidAcresStories(dashbook); addAndroidAcresStories(dashbook);
addBoundariesStories(dashbook); addBoundariesStories(dashbook);
addGoogleWordStories(dashbook); addGoogleWordStories(dashbook);

@ -9,8 +9,8 @@ class AndroidBumperAGame extends BallGame {
: super( : super(
color: const Color(0xFF0000FF), color: const Color(0xFF0000FF),
imagesFileNames: [ imagesFileNames: [
Assets.images.androidBumper.a.lit.keyName, Assets.images.android.bumper.a.lit.keyName,
Assets.images.androidBumper.a.dimmed.keyName, Assets.images.android.bumper.a.dimmed.keyName,
], ],
); );

@ -9,8 +9,8 @@ class AndroidBumperBGame extends BallGame {
: super( : super(
color: const Color(0xFF0000FF), color: const Color(0xFF0000FF),
imagesFileNames: [ imagesFileNames: [
Assets.images.androidBumper.b.lit.keyName, Assets.images.android.bumper.b.lit.keyName,
Assets.images.androidBumper.b.dimmed.keyName, Assets.images.android.bumper.b.dimmed.keyName,
], ],
); );

@ -8,8 +8,8 @@ class AndroidBumperCowGame extends BallGame {
AndroidBumperCowGame() AndroidBumperCowGame()
: super( : super(
imagesFileNames: [ imagesFileNames: [
Assets.images.androidBumper.cow.lit.keyName, Assets.images.android.bumper.cow.lit.keyName,
Assets.images.androidBumper.cow.dimmed.keyName, Assets.images.android.bumper.cow.dimmed.keyName,
], ],
); );

@ -0,0 +1,38 @@
import 'dart:async';
import 'package:flame/input.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class AndroidSpaceshipGame extends BallGame {
AndroidSpaceshipGame()
: super(
ballPriority: RenderPriority.ballOnSpaceship,
ballLayer: Layer.spaceship,
imagesFileNames: [
Assets.images.android.spaceship.saucer.keyName,
Assets.images.android.spaceship.animatronic.keyName,
Assets.images.android.spaceship.lightBeam.keyName,
],
);
static const description = '''
Shows how the AndroidSpaceship is rendered.
- Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a Ball into the game.
''';
@override
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
await addFromBlueprint(
AndroidSpaceship(position: Vector2.zero()),
);
await traceAllBodies();
}
}

@ -1,35 +0,0 @@
import 'dart:async';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/common/common.dart';
class SpaceshipGame extends AssetsGame with TapDetector {
static const description = '''
Shows how a Spaceship works.
- Tap anywhere on the screen to spawn a Ball into the game.
''';
@override
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
await addFromBlueprint(
Spaceship(position: Vector2.zero()),
);
await ready();
}
@override
void onTapUp(TapUpInfo info) {
add(
Ball(baseColor: Colors.blue)
..initialPosition = info.eventPosition.game
..layer = Layer.spaceshipEntranceRamp,
);
}
}

@ -13,8 +13,8 @@ class SpaceshipRailGame extends BallGame {
ballPriority: RenderPriority.ballOnSpaceshipRail, ballPriority: RenderPriority.ballOnSpaceshipRail,
ballLayer: Layer.spaceshipExitRail, ballLayer: Layer.spaceshipExitRail,
imagesFileNames: [ imagesFileNames: [
Assets.images.spaceship.rail.main.keyName, Assets.images.android.rail.main.keyName,
Assets.images.spaceship.rail.exit.keyName, Assets.images.android.rail.exit.keyName,
], ],
); );

@ -14,16 +14,16 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents {
ballPriority: RenderPriority.ballOnSpaceshipRamp, ballPriority: RenderPriority.ballOnSpaceshipRamp,
ballLayer: Layer.spaceshipEntranceRamp, ballLayer: Layer.spaceshipEntranceRamp,
imagesFileNames: [ imagesFileNames: [
Assets.images.spaceship.ramp.railingBackground.keyName, Assets.images.android.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName, Assets.images.android.ramp.main.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName, Assets.images.android.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName, Assets.images.android.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName, Assets.images.android.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName, Assets.images.android.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName, Assets.images.android.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName, Assets.images.android.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName, Assets.images.android.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName, Assets.images.android.ramp.arrow.active5.keyName,
], ],
); );

@ -3,7 +3,7 @@ import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/android_acres/android_bumper_a_game.dart'; import 'package:sandbox/stories/android_acres/android_bumper_a_game.dart';
import 'package:sandbox/stories/android_acres/android_bumper_b_game.dart'; import 'package:sandbox/stories/android_acres/android_bumper_b_game.dart';
import 'package:sandbox/stories/android_acres/android_bumper_cow_game.dart'; import 'package:sandbox/stories/android_acres/android_bumper_cow_game.dart';
import 'package:sandbox/stories/android_acres/spaceship_game.dart'; import 'package:sandbox/stories/android_acres/android_spaceship_game.dart';
import 'package:sandbox/stories/android_acres/spaceship_rail_game.dart'; import 'package:sandbox/stories/android_acres/spaceship_rail_game.dart';
import 'package:sandbox/stories/android_acres/spaceship_ramp_game.dart'; import 'package:sandbox/stories/android_acres/spaceship_ramp_game.dart';
@ -25,9 +25,9 @@ void addAndroidAcresStories(Dashbook dashbook) {
gameBuilder: (_) => AndroidBumperCowGame(), gameBuilder: (_) => AndroidBumperCowGame(),
) )
..addGame( ..addGame(
title: 'Spaceship', title: 'Android Spaceship',
description: SpaceshipGame.description, description: AndroidSpaceshipGame.description,
gameBuilder: (_) => SpaceshipGame(), gameBuilder: (_) => AndroidSpaceshipGame(),
) )
..addGame( ..addGame(
title: 'Spaceship Rail', title: 'Spaceship Rail',

@ -15,7 +15,7 @@ class LaunchRampGame extends BallGame {
); );
static const description = ''' static const description = '''
Shows how LaunchRamp are rendered. Shows how the LaunchRamp is rendered.
- Activate the "trace" parameter to overlay the body. - Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a ball into the game. - Tap anywhere on the screen to spawn a ball into the game.
@ -26,7 +26,7 @@ class LaunchRampGame extends BallGame {
await super.onLoad(); await super.onLoad();
camera camera
..followVector2(Vector2(0, 0)) ..followVector2(Vector2.zero())
..zoom = 7.5; ..zoom = 7.5;
await addFromBlueprint(LaunchRamp()); await addFromBlueprint(LaunchRamp());
await ready(); await ready();

@ -1,11 +0,0 @@
import 'package:dashbook/dashbook.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/sparky_bumper/sparky_bumper_game.dart';
void addSparkyBumperStories(Dashbook dashbook) {
dashbook.storiesOf('Sparky Bumpers').addGame(
title: 'Traced',
description: SparkyBumperGame.description,
gameBuilder: (_) => SparkyBumperGame(),
);
}

@ -9,6 +9,7 @@ class SparkyBumperGame extends BallGame {
Shows how a SparkyBumper is rendered. Shows how a SparkyBumper is rendered.
- Activate the "trace" parameter to overlay the body. - Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a ball into the game.
'''; ''';
@override @override
@ -16,12 +17,12 @@ class SparkyBumperGame extends BallGame {
await super.onLoad(); await super.onLoad();
await images.loadAll([ await images.loadAll([
Assets.images.sparky.bumper.a.active.keyName, Assets.images.sparky.bumper.a.lit.keyName,
Assets.images.sparky.bumper.a.inactive.keyName, Assets.images.sparky.bumper.a.dimmed.keyName,
Assets.images.sparky.bumper.b.active.keyName, Assets.images.sparky.bumper.b.lit.keyName,
Assets.images.sparky.bumper.b.inactive.keyName, Assets.images.sparky.bumper.b.dimmed.keyName,
Assets.images.sparky.bumper.c.active.keyName, Assets.images.sparky.bumper.c.lit.keyName,
Assets.images.sparky.bumper.c.inactive.keyName, Assets.images.sparky.bumper.c.dimmed.keyName,
]); ]);
final center = screenToWorld(camera.viewport.canvasSize! / 2); final center = screenToWorld(camera.viewport.canvasSize! / 2);

@ -0,0 +1,31 @@
import 'dart:async';
import 'package:flame/input.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SparkyComputerGame extends BallGame {
static const description = '''
Shows how the SparkyComputer is rendered.
- Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a ball into the game.
''';
@override
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.sparky.computer.base.keyName,
Assets.images.sparky.computer.top.keyName,
Assets.images.sparky.computer.glow.keyName,
]);
camera.followVector2(Vector2(-10, -40));
await addFromBlueprint(SparkyComputer());
await ready();
await traceAllBodies();
}
}

@ -0,0 +1,18 @@
import 'package:dashbook/dashbook.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/sparky_scorch/sparky_bumper_game.dart';
import 'package:sandbox/stories/sparky_scorch/sparky_computer_game.dart';
void addSparkyScorchStories(Dashbook dashbook) {
dashbook.storiesOf('Sparky Scorch')
..addGame(
title: 'Sparky Computer',
description: SparkyComputerGame.description,
gameBuilder: (_) => SparkyComputerGame(),
)
..addGame(
title: 'Sparky Bumper',
description: SparkyBumperGame.description,
gameBuilder: (_) => SparkyBumperGame(),
);
}

@ -14,4 +14,4 @@ export 'multipliers/stories.dart';
export 'plunger/stories.dart'; export 'plunger/stories.dart';
export 'score_text/stories.dart'; export 'score_text/stories.dart';
export 'slingshot/stories.dart'; export 'slingshot/stories.dart';
export 'sparky_bumper/stories.dart'; export 'sparky_scorch/stories.dart';

@ -13,12 +13,12 @@ import '../../../helpers/helpers.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
final assets = [ final assets = [
Assets.images.androidBumper.a.lit.keyName, Assets.images.android.bumper.a.lit.keyName,
Assets.images.androidBumper.a.dimmed.keyName, Assets.images.android.bumper.a.dimmed.keyName,
Assets.images.androidBumper.b.lit.keyName, Assets.images.android.bumper.b.lit.keyName,
Assets.images.androidBumper.b.dimmed.keyName, Assets.images.android.bumper.b.dimmed.keyName,
Assets.images.androidBumper.cow.lit.keyName, Assets.images.android.bumper.cow.lit.keyName,
Assets.images.androidBumper.cow.dimmed.keyName, Assets.images.android.bumper.cow.dimmed.keyName,
]; ];
final flameTester = FlameTester(() => TestGame(assets)); final flameTester = FlameTester(() => TestGame(assets));

@ -0,0 +1,66 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import '../../helpers/helpers.dart';
void main() {
group('AndroidSpaceship', () {
group('Spaceship', () {
final assets = [
Assets.images.android.spaceship.saucer.keyName,
Assets.images.android.spaceship.animatronic.keyName,
Assets.images.android.spaceship.lightBeam.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
flameTester.test('loads correctly', (game) async {
await game.addFromBlueprint(AndroidSpaceship(position: Vector2.zero()));
await game.ready();
});
flameTester.testGameWidget(
'renders correctly',
setUp: (game, tester) async {
await game.images.loadAll(assets);
await game
.addFromBlueprint(AndroidSpaceship(position: Vector2.zero()));
game.camera.followVector2(Vector2.zero());
await game.ready();
await tester.pump();
},
verify: (game, tester) async {
final animationDuration = game
.descendants()
.whereType<SpriteAnimationComponent>()
.last
.animation!
.totalDuration();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/android_spaceship/start.png'),
);
game.update(animationDuration * 0.5);
await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/android_spaceship/middle.png'),
);
game.update(animationDuration * 0.5);
await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/android_spaceship/end.png'),
);
},
);
});
});
}

@ -0,0 +1,48 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.boardBackground.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
group('BoardBackgroundSpriteComponent', () {
flameTester.test(
'loads correctly',
(game) async {
final boardBackground = BoardBackgroundSpriteComponent();
await game.ensureAdd(boardBackground);
expect(game.contains(boardBackground), isTrue);
},
);
flameTester.testGameWidget(
'renders correctly',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final boardBackground = BoardBackgroundSpriteComponent();
await game.ensureAdd(boardBackground);
await tester.pump();
game.camera
..followVector2(Vector2.zero())
..zoom = 3.7;
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/board-background.png'),
);
},
);
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 209 KiB

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

Loading…
Cancel
Save