diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index b3b964f3..90013646 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -3,6 +3,8 @@ /// FlutterGen /// ***************************************************** +// ignore_for_file: directives_ordering,unnecessary_import + import 'package:flutter/widgets.dart'; class $AssetsImagesGen { @@ -15,8 +17,11 @@ class $AssetsImagesGen { class $AssetsImagesComponentsGen { const $AssetsImagesComponentsGen(); + /// File path: assets/images/components/background.png AssetGenImage get background => const AssetGenImage('assets/images/components/background.png'); + + /// File path: assets/images/components/plunger.png AssetGenImage get plunger => const AssetGenImage('assets/images/components/plunger.png'); } diff --git a/packages/pinball_components/assets/images/google_word/letter1.png b/packages/pinball_components/assets/images/google_word/letter1.png new file mode 100644 index 00000000..f79ea687 Binary files /dev/null and b/packages/pinball_components/assets/images/google_word/letter1.png differ diff --git a/packages/pinball_components/assets/images/google_word/letter2.png b/packages/pinball_components/assets/images/google_word/letter2.png new file mode 100644 index 00000000..e9d205e3 Binary files /dev/null and b/packages/pinball_components/assets/images/google_word/letter2.png differ diff --git a/packages/pinball_components/assets/images/google_word/letter3.png b/packages/pinball_components/assets/images/google_word/letter3.png new file mode 100644 index 00000000..e9d205e3 Binary files /dev/null and b/packages/pinball_components/assets/images/google_word/letter3.png differ diff --git a/packages/pinball_components/assets/images/google_word/letter4.png b/packages/pinball_components/assets/images/google_word/letter4.png new file mode 100644 index 00000000..f79ea687 Binary files /dev/null and b/packages/pinball_components/assets/images/google_word/letter4.png differ diff --git a/packages/pinball_components/assets/images/google_word/letter5.png b/packages/pinball_components/assets/images/google_word/letter5.png new file mode 100644 index 00000000..13f30fb7 Binary files /dev/null and b/packages/pinball_components/assets/images/google_word/letter5.png differ diff --git a/packages/pinball_components/assets/images/google_word/letter6.png b/packages/pinball_components/assets/images/google_word/letter6.png new file mode 100644 index 00000000..7d87654b Binary files /dev/null and b/packages/pinball_components/assets/images/google_word/letter6.png differ diff --git a/packages/pinball_components/lib/gen/assets.gen.dart b/packages/pinball_components/lib/gen/assets.gen.dart index 01b69846..ab64439f 100644 --- a/packages/pinball_components/lib/gen/assets.gen.dart +++ b/packages/pinball_components/lib/gen/assets.gen.dart @@ -28,6 +28,8 @@ class $AssetsImagesGen { AssetGenImage get flutterSignPost => const AssetGenImage('assets/images/flutter_sign_post.png'); + $AssetsImagesGoogleWordGen get googleWord => + const $AssetsImagesGoogleWordGen(); $AssetsImagesKickerGen get kicker => const $AssetsImagesKickerGen(); $AssetsImagesLaunchRampGen get launchRamp => const $AssetsImagesLaunchRampGen(); @@ -118,6 +120,34 @@ class $AssetsImagesFlipperGen { const AssetGenImage('assets/images/flipper/right.png'); } +class $AssetsImagesGoogleWordGen { + const $AssetsImagesGoogleWordGen(); + + /// File path: assets/images/google_word/letter1.png + AssetGenImage get letter1 => + const AssetGenImage('assets/images/google_word/letter1.png'); + + /// File path: assets/images/google_word/letter2.png + AssetGenImage get letter2 => + const AssetGenImage('assets/images/google_word/letter2.png'); + + /// File path: assets/images/google_word/letter3.png + AssetGenImage get letter3 => + const AssetGenImage('assets/images/google_word/letter3.png'); + + /// File path: assets/images/google_word/letter4.png + AssetGenImage get letter4 => + const AssetGenImage('assets/images/google_word/letter4.png'); + + /// File path: assets/images/google_word/letter5.png + AssetGenImage get letter5 => + const AssetGenImage('assets/images/google_word/letter5.png'); + + /// File path: assets/images/google_word/letter6.png + AssetGenImage get letter6 => + const AssetGenImage('assets/images/google_word/letter6.png'); +} + class $AssetsImagesKickerGen { const $AssetsImagesKickerGen(); diff --git a/packages/pinball_components/lib/gen/fonts.gen.dart b/packages/pinball_components/lib/gen/fonts.gen.dart index b15f2dd0..5f77da16 100644 --- a/packages/pinball_components/lib/gen/fonts.gen.dart +++ b/packages/pinball_components/lib/gen/fonts.gen.dart @@ -3,9 +3,14 @@ /// FlutterGen /// ***************************************************** +// ignore_for_file: directives_ordering,unnecessary_import + class FontFamily { FontFamily._(); + /// Font family: PixeloidMono static const String pixeloidMono = 'PixeloidMono'; + + /// Font family: PixeloidSans static const String pixeloidSans = 'PixeloidSans'; } diff --git a/packages/pinball_components/lib/src/components/components.dart b/packages/pinball_components/lib/src/components/components.dart index 9f2c5e67..b5e9392b 100644 --- a/packages/pinball_components/lib/src/components/components.dart +++ b/packages/pinball_components/lib/src/components/components.dart @@ -11,6 +11,7 @@ export 'dino_walls.dart'; export 'fire_effect.dart'; export 'flipper.dart'; export 'flutter_sign_post.dart'; +export 'google_letter.dart'; export 'initial_position.dart'; export 'joint_anchor.dart'; export 'kicker.dart'; diff --git a/packages/pinball_components/lib/src/components/google_letter.dart b/packages/pinball_components/lib/src/components/google_letter.dart new file mode 100644 index 00000000..9e9e2dec --- /dev/null +++ b/packages/pinball_components/lib/src/components/google_letter.dart @@ -0,0 +1,95 @@ +import 'package:flame/components.dart'; +import 'package:flame/effects.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball_components/pinball_components.dart'; + +/// {@template google_letter} +/// Circular sensor that represents a letter in "GOOGLE" for a given index. +/// {@endtemplate} +class GoogleLetter extends BodyComponent with InitialPosition { + /// {@macro google_letter} + GoogleLetter(int index) + : _sprite = _GoogleLetterSprite( + _GoogleLetterSprite.spritePaths[index], + ); + + final _GoogleLetterSprite _sprite; + + /// Activates this [GoogleLetter]. + // TODO(alestiago): Improve doc comment once activate and deactivate + // are implemented with the actual assets. + Future activate() => _sprite.activate(); + + /// Deactivates this [GoogleLetter]. + Future deactivate() => _sprite.deactivate(); + + @override + Future onLoad() async { + await super.onLoad(); + await add(_sprite); + } + + @override + Body createBody() { + final shape = CircleShape()..radius = 1.85; + final fixtureDef = FixtureDef(shape)..isSensor = true; + + final bodyDef = BodyDef() + ..position = initialPosition + ..userData = this + ..type = BodyType.static; + + return world.createBody(bodyDef)..createFixture(fixtureDef); + } +} + +class _GoogleLetterSprite extends SpriteComponent with HasGameRef { + _GoogleLetterSprite(String path) : _path = path; + + static final spritePaths = [ + Assets.images.googleWord.letter1.keyName, + Assets.images.googleWord.letter2.keyName, + Assets.images.googleWord.letter3.keyName, + Assets.images.googleWord.letter4.keyName, + Assets.images.googleWord.letter5.keyName, + Assets.images.googleWord.letter6.keyName, + ]; + + final String _path; + + // TODO(alestiago): Correctly implement activate and deactivate once the + // assets are provided. + Future activate() async { + await add( + _GoogleLetterColorEffect(color: Colors.green), + ); + } + + Future deactivate() async { + await add( + _GoogleLetterColorEffect(color: Colors.red), + ); + } + + @override + Future onLoad() async { + await super.onLoad(); + + final sprite = await gameRef.loadSprite(_path); + this.sprite = sprite; + // TODO(alestiago): Size correctly once the assets are provided. + size = sprite.originalSize / 5; + anchor = Anchor.center; + } +} + +class _GoogleLetterColorEffect extends ColorEffect { + _GoogleLetterColorEffect({ + required Color color, + }) : super( + color, + const Offset(0, 1), + EffectController(duration: 0.25), + ); +} diff --git a/packages/pinball_components/pubspec.yaml b/packages/pinball_components/pubspec.yaml index b8a8b843..d63e2312 100644 --- a/packages/pinball_components/pubspec.yaml +++ b/packages/pinball_components/pubspec.yaml @@ -56,6 +56,7 @@ flutter: - assets/images/sparky/bumper/b/ - assets/images/sparky/bumper/c/ - assets/images/backboard/ + - assets/images/google_word/ flutter_gen: line_length: 80 diff --git a/packages/pinball_components/sandbox/lib/main.dart b/packages/pinball_components/sandbox/lib/main.dart index 74ee5f5e..1e4aab5e 100644 --- a/packages/pinball_components/sandbox/lib/main.dart +++ b/packages/pinball_components/sandbox/lib/main.dart @@ -26,6 +26,7 @@ void main() { addSparkyBumperStories(dashbook); addZoomStories(dashbook); addBoundariesStories(dashbook); + addGoogleWordStories(dashbook); addSpaceshipRampStories(dashbook); addSpaceshipRailStories(dashbook); addLaunchRampStories(dashbook); diff --git a/packages/pinball_components/sandbox/lib/stories/ball/basic_ball_game.dart b/packages/pinball_components/sandbox/lib/stories/ball/basic_ball_game.dart index bfc7a9b0..4fbeae1b 100644 --- a/packages/pinball_components/sandbox/lib/stories/ball/basic_ball_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/ball/basic_ball_game.dart @@ -13,7 +13,7 @@ class BasicBallGame extends BasicGame with TapDetector, Traceable { static const info = ''' Shows how a Ball works. - Tap anywhere on the screen to spawn a ball into the game. + - Tap anywhere on the screen to spawn a ball into the game. '''; final Color color; diff --git a/packages/pinball_components/sandbox/lib/stories/google_word/google_letter_game.dart b/packages/pinball_components/sandbox/lib/stories/google_word/google_letter_game.dart new file mode 100644 index 00000000..ad6e556b --- /dev/null +++ b/packages/pinball_components/sandbox/lib/stories/google_word/google_letter_game.dart @@ -0,0 +1,36 @@ +import 'dart:ui'; + +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:sandbox/stories/ball/basic_ball_game.dart'; + +class GoogleLetterGame extends BasicBallGame { + GoogleLetterGame() : super(color: const Color(0xFF009900)); + + static const info = ''' + Shows how a GoogleLetter is rendered. + + - Tap anywhere on the screen to spawn a ball into the game. +'''; + + @override + Future onLoad() async { + await super.onLoad(); + addContactCallback(_BallGoogleLetterContactCallback()); + + camera.followVector2(Vector2.zero()); + await add(GoogleLetter(0)); + + await traceAllBodies(); + } +} + +class _BallGoogleLetterContactCallback + extends ContactCallback { + @override + void begin(Ball a, GoogleLetter b, Contact contact) { + super.begin(a, b, contact); + b.activate(); + } +} diff --git a/packages/pinball_components/sandbox/lib/stories/google_word/stories.dart b/packages/pinball_components/sandbox/lib/stories/google_word/stories.dart new file mode 100644 index 00000000..290bf9dd --- /dev/null +++ b/packages/pinball_components/sandbox/lib/stories/google_word/stories.dart @@ -0,0 +1,15 @@ +import 'package:dashbook/dashbook.dart'; +import 'package:flame/game.dart'; +import 'package:sandbox/common/common.dart'; +import 'package:sandbox/stories/google_word/google_letter_game.dart'; + +void addGoogleWordStories(Dashbook dashbook) { + dashbook.storiesOf('Google Word').add( + 'Letter', + (context) => GameWidget( + game: GoogleLetterGame()..trace = context.boolProperty('Trace', true), + ), + codeLink: buildSourceLink('google_word/letter.dart'), + info: GoogleLetterGame.info, + ); +} diff --git a/packages/pinball_components/sandbox/lib/stories/stories.dart b/packages/pinball_components/sandbox/lib/stories/stories.dart index c3bbb218..7dd02878 100644 --- a/packages/pinball_components/sandbox/lib/stories/stories.dart +++ b/packages/pinball_components/sandbox/lib/stories/stories.dart @@ -5,6 +5,7 @@ export 'chrome_dino/stories.dart'; export 'effects/stories.dart'; export 'flipper/stories.dart'; export 'flutter_forest/stories.dart'; +export 'google_word/stories.dart'; export 'launch_ramp/stories.dart'; export 'layer/stories.dart'; export 'plunger/stories.dart'; diff --git a/packages/pinball_components/test/src/components/google_letter_test.dart b/packages/pinball_components/test/src/components/google_letter_test.dart new file mode 100644 index 00000000..cdfd3c4a --- /dev/null +++ b/packages/pinball_components/test/src/components/google_letter_test.dart @@ -0,0 +1,126 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame/effects.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 flameTester = FlameTester(TestGame.new); + + group('Google Letter', () { + flameTester.test( + '0th loads correctly', + (game) async { + final googleLetter = GoogleLetter(0); + await game.ready(); + await game.ensureAdd(googleLetter); + + expect(game.contains(googleLetter), isTrue); + }, + ); + + flameTester.test( + '1st loads correctly', + (game) async { + final googleLetter = GoogleLetter(1); + await game.ready(); + await game.ensureAdd(googleLetter); + + expect(game.contains(googleLetter), isTrue); + }, + ); + + flameTester.test( + '2nd loads correctly', + (game) async { + final googleLetter = GoogleLetter(2); + await game.ready(); + await game.ensureAdd(googleLetter); + + expect(game.contains(googleLetter), isTrue); + }, + ); + + flameTester.test( + '3d loads correctly', + (game) async { + final googleLetter = GoogleLetter(3); + await game.ready(); + await game.ensureAdd(googleLetter); + + expect(game.contains(googleLetter), isTrue); + }, + ); + + flameTester.test( + '4th loads correctly', + (game) async { + final googleLetter = GoogleLetter(4); + await game.ready(); + await game.ensureAdd(googleLetter); + + expect(game.contains(googleLetter), isTrue); + }, + ); + + flameTester.test( + '5th loads correctly', + (game) async { + final googleLetter = GoogleLetter(5); + await game.ready(); + await game.ensureAdd(googleLetter); + + expect(game.contains(googleLetter), isTrue); + }, + ); + + test('throws error when index out of range', () { + expect(() => GoogleLetter(-1), throwsA(isA())); + expect(() => GoogleLetter(6), throwsA(isA())); + }); + + group('activate', () { + flameTester.test('returns normally', (game) async { + final googleLetter = GoogleLetter(0); + await game.ensureAdd(googleLetter); + await expectLater(googleLetter.activate, returnsNormally); + }); + + flameTester.test('adds an Effect', (game) async { + final googleLetter = GoogleLetter(0); + await game.ensureAdd(googleLetter); + await googleLetter.activate(); + await game.ready(); + + expect( + googleLetter.descendants().whereType().length, + equals(1), + ); + }); + }); + + group('deactivate', () { + flameTester.test('returns normally', (game) async { + final googleLetter = GoogleLetter(0); + await game.ensureAdd(googleLetter); + await expectLater(googleLetter.deactivate, returnsNormally); + }); + + flameTester.test('adds an Effect', (game) async { + final googleLetter = GoogleLetter(0); + await game.ensureAdd(googleLetter); + await googleLetter.deactivate(); + await game.ready(); + + expect( + googleLetter.descendants().whereType().length, + equals(1), + ); + }); + }); + }); +}