feat: removed attach method for mixin

pull/111/head
alestiago 4 years ago
parent 386c1f93d5
commit 204aa4c0a9

@ -23,9 +23,23 @@ abstract class ComponentController<T extends Component> extends Component {
);
await super.addToParent(parent);
}
}
/// {@template controller}
/// Mixin that attaches a single [ComponentController] to a [Component].
/// {@endtemplate}
mixin Controls<T extends ComponentController> on Component {
/// Builds a [ComponentController] for this [Component].
///
/// **Note**: This method should not be directly called.
T controllerBuilder();
/// Ads the [ComponentController] to its [component].
Future<void> attach() async {
if (parent == null) await component.add(this);
/// The [ComponentController] attached to this [Component].
late final T controller;
@override
Future<void> onLoad() async {
await super.onLoad();
await add(controller = controllerBuilder());
}
}

@ -1,38 +0,0 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/forge2d_game.dart';
import 'package:pinball/flame/flame.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template ball_controller}
/// Controller attached to a [Ball] that handles its game related logic.
/// {@endtemplate}
class BallController extends ComponentController<Ball> {
/// {@macro ball_controller}
BallController(Ball ball) : super(ball);
/// 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() {
component.shouldRemove = true;
}
}
/// {@macro ball_controller}
class PlungerBallController extends BallController
with HasGameRef<PinballGame> {
/// {@macro ball_controller}
PlungerBallController(Ball<Forge2DGame> ball) : super(ball);
@override
void lost() {
super.lost();
final bloc = gameRef.read<GameBloc>()..add(const BallLost());
final shouldBallRespwan = !bloc.state.isLastBall && !bloc.state.isGameOver;
if (shouldBallRespwan) gameRef.spawnBall();
}
}

@ -94,10 +94,9 @@ class _BottomGroupSide extends Component {
Future<void> onLoad() async {
final direction = _side.direction;
final flipper = Flipper(
final flipper = ControlledFlipper(
side: _side,
)..initialPosition = _position;
await FlipperController(flipper).attach();
final baseboard = Baseboard(side: _side)
..initialPosition = _position +

@ -1,8 +1,8 @@
export 'ball_controller.dart';
export 'baseboard.dart';
export 'board.dart';
export 'bonus_word.dart';
export 'chrome_dino.dart';
export 'controlled_ball.dart';
export 'flipper_controller.dart';
export 'flutter_forest.dart';
export 'jetpack_ramp.dart';

@ -0,0 +1,97 @@
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame_forge2d/forge2d_game.dart';
import 'package:pinball/flame/flame.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template controlled_ball}
/// A [Ball] with a [BallController] attached.
/// {@endtemplate}
abstract class _ControlledBall<T extends BallController> extends Ball
with Controls<T> {
_ControlledBall({required Color baseColor}) : super(baseColor: baseColor);
}
/// {@template plunger_ball}
/// A [Ball] that starts at the [Plunger].
///
/// When a [PlungerBall] is lost, it will decrease the [GameState.balls] count,
/// and a new [PlungerBall] is spawned if it's possible.
/// {@endtemplate}
class PlungerBall extends _ControlledBall<PlungerBallController> {
// TODO(alestiago): Work on a better solution than passing the game.
/// {@macro plunger_ball}
PlungerBall(
PinballGame game, {
required Plunger plunger,
}) : super(baseColor: game.theme.characterTheme.ballColor) {
// TODO(alestiago): Dicuss if this is a good idea.
initialPosition = Vector2(
plunger.body.position.x,
plunger.body.position.y + Ball.size.y,
);
}
@override
PlungerBallController controllerBuilder() => PlungerBallController(this);
}
/// {@template bonus_ball}
/// {@macro controlled_ball}
///
/// When a [BonusBall] is lost, the [GameState.balls] doesn't change.
/// {@endtemplate}
class BonusBall extends _ControlledBall<BallController> {
/// {@macro bonus_ball}
BonusBall(PinballGame game)
: super(baseColor: game.theme.characterTheme.ballColor);
@override
BallController controllerBuilder() => BallController(this);
}
/// {@template debug_ball}
/// [Ball] used in [DebugPinballGame].
/// {@endtemplate}
class DebugBall extends _ControlledBall<BallController> {
/// {@macro debug_ball}
DebugBall() : super(baseColor: const Color(0xFFFF0000));
@override
BallController controllerBuilder() => BallController(this);
}
/// {@template ball_controller}
/// Controller attached to a [Ball] that handles its game related logic.
/// {@endtemplate}
class BallController extends ComponentController<Ball> {
/// {@macro ball_controller}
BallController(Ball ball) : super(ball);
/// 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() {
component.shouldRemove = true;
}
}
/// {@macro ball_controller}
class PlungerBallController extends BallController
with HasGameRef<PinballGame> {
/// {@macro ball_controller}
PlungerBallController(Ball<Forge2DGame> ball) : super(ball);
@override
void lost() {
super.lost();
final bloc = gameRef.read<GameBloc>()..add(const BallLost());
final shouldBallRespwan = !bloc.state.isLastBall && !bloc.state.isGameOver;
if (shouldBallRespwan) gameRef.spawnBall();
}
}

@ -3,6 +3,17 @@ import 'package:flutter/services.dart';
import 'package:pinball/flame/flame.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template controlled_flipper}
/// A [Flipper] with a [FlipperController] attached.
/// {@endtemplate}
class ControlledFlipper extends Flipper with Controls<FlipperController> {
/// {@macro controlled_flipper}
ControlledFlipper({required BoardSide side}) : super(side: side);
@override
FlipperController controllerBuilder() => FlipperController(this);
}
/// {@template flipper_controller}
/// A [ComponentController] that controls a [Flipper]s movement.
/// {@endtemplate}

@ -32,11 +32,9 @@ class FlutterForest extends Component
void onNewState(GameState state) {
super.onNewState(state);
final ball = Ball(
baseColor: gameRef.theme.characterTheme.ballColor,
)..initialPosition = Vector2(17.2, 52.7);
BallController(ball).attach();
gameRef.add(ball);
add(
BonusBall(gameRef)..initialPosition = Vector2(17.2, 52.7),
);
}
@override

@ -101,13 +101,7 @@ class PinballGame extends Forge2DGame
}
void spawnBall() {
final ball = Ball(
baseColor: theme.characterTheme.ballColor,
)..initialPosition = Vector2(
plunger.body.position.x,
plunger.body.position.y + Ball.size.y,
);
PlungerBallController(ball).attach();
final ball = PlungerBall(this, plunger: plunger);
add(ball);
}
}
@ -140,9 +134,8 @@ class DebugPinballGame extends PinballGame with TapDetector {
@override
void onTapUp(TapUpInfo info) {
final ball = Ball(baseColor: const Color(0xFFFF0000))
..initialPosition = info.eventPosition.game;
BallController(ball).attach();
add(ball);
add(
DebugBall()..initialPosition = info.eventPosition.game,
);
}
}

@ -37,36 +37,5 @@ void main() {
);
},
);
group('attach', () {
flameTester.test(
'adds component controller to controlled component',
(game) async {
final component = Component();
final controller = TestComponentController(component);
await controller.attach();
await game.add(component);
await game.ready();
expect(component.contains(controller), isTrue);
},
);
flameTester.test(
"doesn't fail when already has a parent",
(game) async {
final component = Component();
final controller = TestComponentController(component);
await controller.attach();
await expectLater(
() async => controller.attach(),
returnsNormally,
);
},
);
});
});
}

@ -27,7 +27,7 @@ void main() {
(game) async {
await game.add(ball);
final controller = BallController(ball);
await controller.attach();
await ball.add(controller);
await game.ready();
controller.lost();
@ -63,7 +63,7 @@ void main() {
(game, tester) async {
await game.add(ball);
final controller = PlungerBallController(ball);
await controller.attach();
await ball.add(controller);
await game.ready();
controller.lost();
@ -77,7 +77,7 @@ void main() {
'adds BallLost to GameBloc',
(game, tester) async {
final controller = PlungerBallController(ball);
await controller.attach();
await ball.add(controller);
await game.add(ball);
await game.ready();
@ -91,7 +91,7 @@ void main() {
'adds a new ball if the game is not over',
(game, tester) async {
final controller = PlungerBallController(ball);
await controller.attach();
await ball.add(controller);
await game.add(ball);
await game.ready();
@ -122,7 +122,7 @@ void main() {
),
);
final controller = BallController(ball);
await controller.attach();
await ball.add(controller);
await game.add(ball);
await game.ready();
Loading…
Cancel
Save