diff --git a/analysis_options.yaml b/analysis_options.yaml index 07aa1dab..44aef9ac 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1 @@ include: package:very_good_analysis/analysis_options.2.4.0.yaml -linter: - rules: - public_member_api_docs: false diff --git a/assets/images/components/flipper.png b/assets/images/components/flipper.png new file mode 100644 index 00000000..f63974c4 Binary files /dev/null and b/assets/images/components/flipper.png differ diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index 7e3fdf17..cf6213e9 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -5,6 +5,8 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +// ignore_for_file: public_member_api_docs + import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:pinball/l10n/l10n.dart'; diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart index c612b584..34fcc47a 100644 --- a/lib/bootstrap.dart +++ b/lib/bootstrap.dart @@ -5,6 +5,8 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +// ignore_for_file: public_member_api_docs + import 'dart:async'; import 'dart:developer'; diff --git a/lib/game/bloc/game_bloc.dart b/lib/game/bloc/game_bloc.dart index 3b5c16b0..31aa0498 100644 --- a/lib/game/bloc/game_bloc.dart +++ b/lib/game/bloc/game_bloc.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs + import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; diff --git a/lib/game/bloc/game_event.dart b/lib/game/bloc/game_event.dart index 417f6322..fa57cbff 100644 --- a/lib/game/bloc/game_event.dart +++ b/lib/game/bloc/game_event.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs + part of 'game_bloc.dart'; @immutable @@ -5,16 +7,22 @@ abstract class GameEvent extends Equatable { const GameEvent(); } +/// {@template ball_lost_game_event} /// Event added when a user drops a ball off the screen. +/// {@endtemplate} class BallLost extends GameEvent { + /// {@macro ball_lost_game_event} const BallLost(); @override List get props => []; } +/// {@template scored_game_event} /// Event added when a user increases their score. +/// {@endtemplate} class Scored extends GameEvent { + /// {@macro scored_game_event} const Scored({ required this.points, }) : assert(points > 0, 'Points must be greater than 0'); diff --git a/lib/game/bloc/game_state.dart b/lib/game/bloc/game_state.dart index 8a5ab298..f8456518 100644 --- a/lib/game/bloc/game_state.dart +++ b/lib/game/bloc/game_state.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs + part of 'game_bloc.dart'; /// {@template game_state} diff --git a/lib/game/components/ball.dart b/lib/game/components/ball.dart index 52a31827..20aa924e 100644 --- a/lib/game/components/ball.dart +++ b/lib/game/components/ball.dart @@ -2,16 +2,23 @@ import 'package:flame/components.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:pinball/game/game.dart'; +/// {@template ball} +/// A solid, [BodyType.dynamic] sphere that rolls and bounces along the +/// [PinballGame]. +/// {@endtemplate} class Ball extends PositionBodyComponent { + /// {@macro ball} Ball({ required Vector2 position, }) : _position = position, - super(size: ballSize); - - static final ballSize = Vector2.all(2); + super(size: Vector2.all(2)); + /// The initial position of the [Ball] body. final Vector2 _position; + /// Asset location of the sprite that renders with the [Ball]. + /// + /// Sprite is preloaded by [PinballGameAssetsX]. static const spritePath = 'components/ball.png'; @override @@ -19,13 +26,12 @@ class Ball extends PositionBodyComponent { await super.onLoad(); final sprite = await gameRef.loadSprite(spritePath); final tint = gameRef.theme.characterTheme.ballColor.withOpacity(0.5); - positionComponent = SpriteComponent(sprite: sprite, size: ballSize) - ..tint(tint); + positionComponent = SpriteComponent(sprite: sprite, size: size)..tint(tint); } @override Body createBody() { - final shape = CircleShape()..radius = ballSize.x / 2; + final shape = CircleShape()..radius = size.x / 2; final fixtureDef = FixtureDef(shape)..density = 1; @@ -37,6 +43,11 @@ class Ball extends PositionBodyComponent { return world.createBody(bodyDef)..createFixture(fixtureDef); } + /// Removes the [Ball] from a [PinballGame]; spawning a new [Ball] if + /// any are left. + /// + /// Triggered by [BottomWallBallContactCallback] when the [Ball] falls into + /// a [BottomWall]. void lost() { shouldRemove = true; diff --git a/lib/game/components/flipper.dart b/lib/game/components/flipper.dart index bd071b93..16754ed3 100644 --- a/lib/game/components/flipper.dart +++ b/lib/game/components/flipper.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'dart:math' as math; +import 'package:flame/components.dart' show SpriteComponent; import 'package:flame/input.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:pinball/game/game.dart'; @@ -12,19 +12,15 @@ import 'package:pinball/game/game.dart'; /// /// [Flipper] can be controlled by the player in an arc motion. /// {@endtemplate flipper} -class Flipper extends BodyComponent with KeyboardHandler { +class Flipper extends PositionBodyComponent with KeyboardHandler { /// {@macro flipper} Flipper._({ required Vector2 position, required this.side, required List keys, }) : _position = position, - _keys = keys { - // TODO(alestiago): Use sprite instead of color when provided. - paint = Paint() - ..color = const Color(0xFF00FF00) - ..style = PaintingStyle.fill; - } + _keys = keys, + super(size: Vector2(width, height)); /// A left positioned [Flipper]. Flipper.left({ @@ -50,6 +46,11 @@ class Flipper extends BodyComponent with KeyboardHandler { ], ); + /// Asset location of the sprite that renders with the [Flipper]. + /// + /// Sprite is preloaded by [PinballGameAssetsX]. + static const spritePath = 'components/flipper.png'; + /// The width of the [Flipper]. static const width = 12.0; @@ -75,6 +76,20 @@ class Flipper extends BodyComponent with KeyboardHandler { /// [onKeyEvent] method listens to when one of these keys is pressed. final List _keys; + @override + Future onLoad() async { + await super.onLoad(); + final sprite = await gameRef.loadSprite(spritePath); + positionComponent = SpriteComponent( + sprite: sprite, + size: size, + ); + + if (side == BoardSide.right) { + positionComponent?.flipHorizontally(); + } + } + /// Applies downward linear velocity to the [Flipper], moving it to its /// resting position. void _moveDown() { @@ -148,6 +163,7 @@ class Flipper extends BodyComponent with KeyboardHandler { // TODO(erickzanardo): Remove this once the issue is solved: // https://github.com/flame-engine/flame/issues/1417 + // ignore: public_member_api_docs final Completer hasMounted = Completer(); @override diff --git a/lib/game/components/wall.dart b/lib/game/components/wall.dart index b784b8cb..f5a15af5 100644 --- a/lib/game/components/wall.dart +++ b/lib/game/components/wall.dart @@ -6,13 +6,18 @@ import 'package:pinball/game/components/components.dart'; /// {@template wall} /// A continuos generic and [BodyType.static] barrier that divides a game area. /// {@endtemplate} +// TODO(alestiago): Remove [Wall] for [Pathway.straight]. class Wall extends BodyComponent { + /// {@macro wall} Wall({ required this.start, required this.end, }); + /// The [start] of the [Wall]. final Vector2 start; + + /// The [end] of the [Wall]. final Vector2 end; @override @@ -39,6 +44,7 @@ class Wall extends BodyComponent { /// [BottomWallBallContactCallback]. /// {@endtemplate} class BottomWall extends Wall { + /// {@macro bottom_wall} BottomWall(Forge2DGame game) : super( start: game.screenToWorld(game.camera.viewport.effectiveSize), diff --git a/lib/game/game_assets.dart b/lib/game/game_assets.dart index 964aeda1..778e2bc2 100644 --- a/lib/game/game_assets.dart +++ b/lib/game/game_assets.dart @@ -6,6 +6,7 @@ extension PinballGameAssetsX on PinballGame { Future preLoadAssets() async { await Future.wait([ images.load(Ball.spritePath), + images.load(Flipper.spritePath), ]); } } diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 7231f315..5854422c 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs + import 'dart:async'; import 'package:flame/input.dart'; import 'package:flame_bloc/flame_bloc.dart'; diff --git a/lib/game/view/pinball_game_page.dart b/lib/game/view/pinball_game_page.dart index 3801fcb1..95997832 100644 --- a/lib/game/view/pinball_game_page.dart +++ b/lib/game/view/pinball_game_page.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs + import 'package:flame/game.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/lib/game/view/widgets/game_over_dialog.dart b/lib/game/view/widgets/game_over_dialog.dart index 586d6c56..9d1c61b0 100644 --- a/lib/game/view/widgets/game_over_dialog.dart +++ b/lib/game/view/widgets/game_over_dialog.dart @@ -1,6 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:pinball/game/game.dart'; +/// {@template game_over_dialog} +/// [Dialog] displayed when the [PinballGame] is over. +/// {@endtemplate} class GameOverDialog extends StatelessWidget { + /// {@macro game_over_dialog} const GameOverDialog({Key? key}) : super(key: key); @override diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 766b5e31..548a81a6 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -5,6 +5,8 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +// ignore_for_file: public_member_api_docs + import 'package:flutter/widgets.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; diff --git a/lib/landing/view/landing_page.dart b/lib/landing/view/landing_page.dart index 56bd53bc..38951da6 100644 --- a/lib/landing/view/landing_page.dart +++ b/lib/landing/view/landing_page.dart @@ -1,3 +1,5 @@ +// ignore_for_file: public_member_api_docs + import 'package:flutter/material.dart'; import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/theme/theme.dart'; diff --git a/lib/theme/cubit/theme_cubit.dart b/lib/theme/cubit/theme_cubit.dart index 7ba79e59..94eba4a6 100644 --- a/lib/theme/cubit/theme_cubit.dart +++ b/lib/theme/cubit/theme_cubit.dart @@ -1,3 +1,6 @@ +// ignore_for_file: public_member_api_docs +// TODO(allisonryan0002): Document this section when the API is stable. + import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:pinball_theme/pinball_theme.dart'; diff --git a/lib/theme/cubit/theme_state.dart b/lib/theme/cubit/theme_state.dart index 13b3ea5f..078f5c84 100644 --- a/lib/theme/cubit/theme_state.dart +++ b/lib/theme/cubit/theme_state.dart @@ -1,3 +1,6 @@ +// ignore_for_file: public_member_api_docs +// TODO(allisonryan0002): Document this section when the API is stable. + part of 'theme_cubit.dart'; class ThemeState extends Equatable { diff --git a/test/game/components/anchor_test.dart b/test/game/components/anchor_test.dart index 1381cd19..e0cfd645 100644 --- a/test/game/components/anchor_test.dart +++ b/test/game/components/anchor_test.dart @@ -17,6 +17,7 @@ void main() { 'loads correctly', (game) async { final anchor = Anchor(position: Vector2.zero()); + await game.ready(); await game.ensureAdd(anchor); expect(game.contains(anchor), isTrue); @@ -27,6 +28,7 @@ void main() { flameTester.test( 'positions correctly', (game) async { + await game.ready(); final position = Vector2.all(10); final anchor = Anchor(position: position); await game.ensureAdd(anchor); @@ -39,6 +41,7 @@ void main() { flameTester.test( 'is static', (game) async { + await game.ready(); final anchor = Anchor(position: Vector2.zero()); await game.ensureAdd(anchor); diff --git a/test/game/components/pathway_test.dart b/test/game/components/pathway_test.dart index 75478bf6..482f6d57 100644 --- a/test/game/components/pathway_test.dart +++ b/test/game/components/pathway_test.dart @@ -20,6 +20,7 @@ void main() { flameTester.test( 'has transparent color by default when no color is specified', (game) async { + await game.ready(); final pathway = Pathway.straight( position: Vector2.zero(), start: Vector2(10, 10), @@ -40,6 +41,7 @@ void main() { flameTester.test( 'has a color when is specified', (game) async { + await game.ready(); const defaultColor = Colors.blue; final pathway = Pathway.straight( @@ -61,6 +63,7 @@ void main() { flameTester.test( 'loads correctly', (game) async { + await game.ready(); final pathway = Pathway.straight( position: Vector2.zero(), start: Vector2(10, 10), @@ -77,6 +80,7 @@ void main() { flameTester.test( 'positions correctly', (game) async { + await game.ready(); final position = Vector2.all(10); final pathway = Pathway.straight( position: position, @@ -94,6 +98,7 @@ void main() { flameTester.test( 'is static', (game) async { + await game.ready(); final pathway = Pathway.straight( position: Vector2.zero(), start: Vector2(10, 10), @@ -111,6 +116,7 @@ void main() { flameTester.test( 'has only one ChainShape when singleWall is true', (game) async { + await game.ready(); final pathway = Pathway.straight( position: Vector2.zero(), start: Vector2(10, 10), @@ -130,6 +136,7 @@ void main() { flameTester.test( 'has two ChainShape when singleWall is false (default)', (game) async { + await game.ready(); final pathway = Pathway.straight( position: Vector2.zero(), start: Vector2(10, 10), @@ -152,6 +159,7 @@ void main() { flameTester.test( 'loads correctly', (game) async { + await game.ready(); final pathway = Pathway.arc( position: Vector2.zero(), width: width, @@ -168,6 +176,7 @@ void main() { flameTester.test( 'positions correctly', (game) async { + await game.ready(); final position = Vector2.all(10); final pathway = Pathway.arc( position: position, @@ -185,6 +194,7 @@ void main() { flameTester.test( 'is static', (game) async { + await game.ready(); final pathway = Pathway.arc( position: Vector2.zero(), width: width, @@ -210,6 +220,7 @@ void main() { flameTester.test( 'loads correctly', (game) async { + await game.ready(); final pathway = Pathway.bezierCurve( position: Vector2.zero(), controlPoints: controlPoints, @@ -225,6 +236,7 @@ void main() { flameTester.test( 'positions correctly', (game) async { + await game.ready(); final position = Vector2.all(10); final pathway = Pathway.bezierCurve( position: position, @@ -241,6 +253,7 @@ void main() { flameTester.test( 'is static', (game) async { + await game.ready(); final pathway = Pathway.bezierCurve( position: Vector2.zero(), controlPoints: controlPoints, diff --git a/test/game/components/plunger_test.dart b/test/game/components/plunger_test.dart index 2f6070ba..17bc275e 100644 --- a/test/game/components/plunger_test.dart +++ b/test/game/components/plunger_test.dart @@ -16,6 +16,7 @@ void main() { flameTester.test( 'loads correctly', (game) async { + await game.ready(); final plunger = Plunger(position: Vector2.zero()); await game.ensureAdd(plunger); diff --git a/test/game/components/wall_test.dart b/test/game/components/wall_test.dart index 0384407a..c19f20e8 100644 --- a/test/game/components/wall_test.dart +++ b/test/game/components/wall_test.dart @@ -37,6 +37,7 @@ void main() { flameTester.test( 'loads correctly', (game) async { + await game.ready(); final wall = Wall( start: Vector2.zero(), end: Vector2(100, 0),