From 05e3049205c1f78266345d38bb57fcabd2789329 Mon Sep 17 00:00:00 2001 From: RuiAlonso Date: Thu, 28 Apr 2022 14:16:32 +0200 Subject: [PATCH] refactor: multipliers cubit --- .../multipliers/behaviors/behaviors.dart | 1 + .../behaviors/multipliers_behavior.dart | 26 ++++++ .../components/multipliers/multipliers.dart | 43 +++++++++ .../lib/src/components/components.dart | 2 +- .../multiplier/cubit/multiplier_cubit.dart | 47 ++++++++++ .../multiplier/cubit/multiplier_state.dart | 35 ++++++++ .../{ => multiplier}/multiplier.dart | 87 ++++++++++--------- 7 files changed, 198 insertions(+), 43 deletions(-) create mode 100644 lib/game/components/multipliers/behaviors/behaviors.dart create mode 100644 lib/game/components/multipliers/behaviors/multipliers_behavior.dart create mode 100644 lib/game/components/multipliers/multipliers.dart create mode 100644 packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_cubit.dart create mode 100644 packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_state.dart rename packages/pinball_components/lib/src/components/{ => multiplier}/multiplier.dart (63%) diff --git a/lib/game/components/multipliers/behaviors/behaviors.dart b/lib/game/components/multipliers/behaviors/behaviors.dart new file mode 100644 index 00000000..70703bba --- /dev/null +++ b/lib/game/components/multipliers/behaviors/behaviors.dart @@ -0,0 +1 @@ +export 'multipliers_behavior.dart'; diff --git a/lib/game/components/multipliers/behaviors/multipliers_behavior.dart b/lib/game/components/multipliers/behaviors/multipliers_behavior.dart new file mode 100644 index 00000000..6912ece8 --- /dev/null +++ b/lib/game/components/multipliers/behaviors/multipliers_behavior.dart @@ -0,0 +1,26 @@ +import 'package:flame/components.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +/// Toggle each [Multiplier] when GameState.multiplier changes. +class MultipliersBehavior extends Component + with HasGameRef, ParentIsA { + @override + void onMount() { + super.onMount(); + + // TODO(ruimiguel): filter only when multiplier has change, not every other + // state. + gameRef.read().stream.listen((state) { + final multipliers = parent.children.whereType(); + for (final multiplier in multipliers) { + // TODO(ruimiguel): use here GameState.multiplier when merged + // https://github.com/VGVentures/pinball/pull/213. + final currentMultiplier = state.score.bitLength % 6 + 1; + + multiplier.bloc.toggle(currentMultiplier); + } + }); + } +} diff --git a/lib/game/components/multipliers/multipliers.dart b/lib/game/components/multipliers/multipliers.dart new file mode 100644 index 00000000..015d210f --- /dev/null +++ b/lib/game/components/multipliers/multipliers.dart @@ -0,0 +1,43 @@ +// ignore_for_file: public_member_api_docs + +import 'dart:math' as math; +import 'package:flame/components.dart'; +import 'package:pinball/game/components/multipliers/behaviors/behaviors.dart'; +import 'package:pinball_components/pinball_components.dart'; + +/// {@template multipliers_component} +/// A group for the multipliers over the board. +/// {@endtemplate} +class Multipliers extends Component { + /// {@macro multipliers_component} + Multipliers() + : super( + children: [ + Multiplier( + value: MultiplierValue.x2, + position: Vector2(-19.5, -2), + rotation: -15 * math.pi / 180, + ), + Multiplier( + value: MultiplierValue.x3, + position: Vector2(13, -9.4), + rotation: 15 * math.pi / 180, + ), + Multiplier( + value: MultiplierValue.x4, + position: Vector2(0, -21.2), + ), + Multiplier( + value: MultiplierValue.x5, + position: Vector2(-8.5, -28), + rotation: -3 * math.pi / 180, + ), + Multiplier( + value: MultiplierValue.x6, + position: Vector2(10, -30.7), + rotation: 8 * math.pi / 180, + ), + MultipliersBehavior(), + ], + ); +} diff --git a/packages/pinball_components/lib/src/components/components.dart b/packages/pinball_components/lib/src/components/components.dart index 75c59a77..72e87c21 100644 --- a/packages/pinball_components/lib/src/components/components.dart +++ b/packages/pinball_components/lib/src/components/components.dart @@ -19,7 +19,7 @@ export 'kicker.dart'; export 'launch_ramp.dart'; export 'layer.dart'; export 'layer_sensor.dart'; -export 'multiplier.dart'; +export 'multiplier/multiplier.dart'; export 'plunger.dart'; export 'render_priority.dart'; export 'rocket.dart'; diff --git a/packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_cubit.dart b/packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_cubit.dart new file mode 100644 index 00000000..af0da7b1 --- /dev/null +++ b/packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_cubit.dart @@ -0,0 +1,47 @@ +// ignore_for_file: public_member_api_docs + +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:pinball_components/pinball_components.dart'; + +part 'multiplier_state.dart'; + +class MultiplierCubit extends Cubit { + MultiplierCubit(MultiplierValue multiplierValue) + : super( + MultiplierState( + value: multiplierValue, + spriteState: MultiplierSpriteState.dimmed, + ), + ); + + /// Event added when the game current multiplier changes. + void toggle(int multiplier) { + if (state.equalsTo(multiplier)) { + if (state.spriteState == MultiplierSpriteState.dimmed) { + emit(state.copyWith(spriteState: MultiplierSpriteState.lit)); + } + } else { + if (state.spriteState == MultiplierSpriteState.lit) { + emit(state.copyWith(spriteState: MultiplierSpriteState.dimmed)); + } + } + } +} + +extension on MultiplierState { + bool equalsTo(int value) { + switch (this.value) { + case MultiplierValue.x2: + return value == 2; + case MultiplierValue.x3: + return value == 3; + case MultiplierValue.x4: + return value == 4; + case MultiplierValue.x5: + return value == 5; + case MultiplierValue.x6: + return value == 6; + } + } +} diff --git a/packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_state.dart b/packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_state.dart new file mode 100644 index 00000000..67ab0c87 --- /dev/null +++ b/packages/pinball_components/lib/src/components/multiplier/cubit/multiplier_state.dart @@ -0,0 +1,35 @@ +// ignore_for_file: public_member_api_docs + +part of 'multiplier_cubit.dart'; + +/// Indicates the different sprite states for [MultiplierSpriteGroupComponent]. +enum MultiplierSpriteState { + lit, + dimmed, +} + +/// Indicates the [MultiplierCubit]'s current state. +class MultiplierState extends Equatable { + const MultiplierState({ + required this.value, + required this.spriteState, + }); + + /// Current value for the [Multiplier] + final MultiplierValue value; + + /// The [MultiplierSpriteGroupComponent] current sprite state + final MultiplierSpriteState spriteState; + + MultiplierState copyWith({ + MultiplierSpriteState? spriteState, + }) { + return MultiplierState( + value: value, + spriteState: spriteState ?? this.spriteState, + ); + } + + @override + List get props => [value, spriteState]; +} diff --git a/packages/pinball_components/lib/src/components/multiplier.dart b/packages/pinball_components/lib/src/components/multiplier/multiplier.dart similarity index 63% rename from packages/pinball_components/lib/src/components/multiplier.dart rename to packages/pinball_components/lib/src/components/multiplier/multiplier.dart index 04bde651..3bf75ec7 100644 --- a/packages/pinball_components/lib/src/components/multiplier.dart +++ b/packages/pinball_components/lib/src/components/multiplier/multiplier.dart @@ -3,6 +3,10 @@ import 'package:flame/components.dart'; import 'package:flutter/material.dart'; import 'package:pinball_components/gen/assets.gen.dart'; +import 'package:pinball_components/src/components/multiplier/cubit/multiplier_cubit.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +export 'cubit/multiplier_cubit.dart'; /// {@template multiplier} /// A [Component] for the multiplier over the board. @@ -14,29 +18,50 @@ class Multiplier extends Component { required Vector2 position, double rotation = 0, }) : _value = value, - _sprite = MultiplierSpriteGroupComponent( - position: position, - litAssetPath: value.litAssetPath, - dimmedAssetPath: value.dimmedAssetPath, - rotation: rotation, - ); + _position = position, + _rotation = rotation, + bloc = MultiplierCubit(value), + super(); final MultiplierValue _value; - final MultiplierSpriteGroupComponent _sprite; + final Vector2 _position; + final double _rotation; + late final MultiplierSpriteGroupComponent _sprite; + + /// Creates a [Multiplier] without any children. + /// + /// This can be used for testing [Multiplier]'s behaviors in isolation. + // TODO(alestiago): Refactor injecting bloc once the following is merged: + // https://github.com/flame-engine/flame/pull/1538 + @visibleForTesting + Multiplier.test({ + required MultiplierValue value, + required this.bloc, + }) : _value = value, + _position = Vector2.zero(), + _rotation = 0; - /// Change current [Sprite] to active or inactive depending on applied - /// multiplier. - void toggle(int multiplier) { - if (_value.equalsTo(multiplier)) { - _sprite.current = MultiplierSpriteState.lit; - } else { - _sprite.current = MultiplierSpriteState.dimmed; - } +// TODO(ruimiguel): Consider refactoring once the following is merged: + // https://github.com/flame-engine/flame/pull/1538 + // ignore: public_member_api_docs + final MultiplierCubit bloc; + + @override + void onRemove() { + bloc.close(); + super.onRemove(); } @override Future onLoad() async { await super.onLoad(); + _sprite = MultiplierSpriteGroupComponent( + position: _position, + litAssetPath: _value.litAssetPath, + dimmedAssetPath: _value.dimmedAssetPath, + rotation: _rotation, + current: bloc.state, + ); await add(_sprite); } } @@ -50,15 +75,6 @@ enum MultiplierValue { x6, } -/// Indicates the current sprite state of the multiplier. -enum MultiplierSpriteState { - /// A lit up bumper. - lit, - - /// A dimmed bumper. - dimmed, -} - extension on MultiplierValue { String get litAssetPath { switch (this) { @@ -89,21 +105,6 @@ extension on MultiplierValue { return Assets.images.multiplier.x6.dimmed.keyName; } } - - bool equalsTo(int value) { - switch (this) { - case MultiplierValue.x2: - return value == 2; - case MultiplierValue.x3: - return value == 3; - case MultiplierValue.x4: - return value == 4; - case MultiplierValue.x5: - return value == 5; - case MultiplierValue.x6: - return value == 6; - } - } } /// {@template multiplier_sprite_group_component} @@ -111,19 +112,22 @@ extension on MultiplierValue { /// {@endtemplate} @visibleForTesting class MultiplierSpriteGroupComponent - extends SpriteGroupComponent with HasGameRef { + extends SpriteGroupComponent + with HasGameRef, ParentIsA { /// {@macro multiplier_sprite_group_component} MultiplierSpriteGroupComponent({ required Vector2 position, required String litAssetPath, required String dimmedAssetPath, required double rotation, + required MultiplierState current, }) : _litAssetPath = litAssetPath, _dimmedAssetPath = dimmedAssetPath, super( anchor: Anchor.center, position: position, angle: rotation, + current: current.spriteState, ); final String _litAssetPath; @@ -132,6 +136,7 @@ class MultiplierSpriteGroupComponent @override Future onLoad() async { await super.onLoad(); + parent.bloc.stream.listen((state) => current = state.spriteState); final sprites = { MultiplierSpriteState.lit: @@ -140,8 +145,6 @@ class MultiplierSpriteGroupComponent Sprite(gameRef.images.fromCache(_dimmedAssetPath)), }; this.sprites = sprites; - - current = MultiplierSpriteState.dimmed; size = sprites[current]!.originalSize / 10; } }