refactor: moved arrow state to cubit inside ramp instead of propagate from behavior

pull/296/head
RuiAlonso 3 years ago
parent 6dd5c2c73f
commit c9d3db44b1

@ -21,8 +21,6 @@ class RampShotBehavior extends Component
super.onMount();
parent.bloc.stream.listen((state) {
parent.progress();
final achievedOneMillionPoints = state.hits % 10 == 0;
if (!achievedOneMillionPoints) {

@ -9,9 +9,14 @@ class SpaceshipRampCubit extends Cubit<SpaceshipRampState> {
SpaceshipRampCubit() : super(const SpaceshipRampState.initial());
void onBallInside() {
final index =
SpaceshipRampArrowSpriteState.values.indexOf(state.arrowState);
emit(
state.copyWith(
hits: state.hits + 1,
arrowState: SpaceshipRampArrowSpriteState
.values[(index + 1) % SpaceshipRampArrowSpriteState.values.length],
),
);
}

@ -2,23 +2,51 @@
part of 'spaceship_ramp_cubit.dart';
enum SpaceshipRampArrowSpriteState {
/// Arrow with no dashes lit up.
inactive,
/// Arrow with 1 light lit up.
active1,
/// Arrow with 2 lights lit up.
active2,
/// Arrow with 3 lights lit up.
active3,
/// Arrow with 4 lights lit up.
active4,
/// Arrow with all 5 lights lit up.
active5,
}
class SpaceshipRampState extends Equatable {
const SpaceshipRampState({
required this.hits,
required this.arrowState,
}) : assert(hits >= 0, "Hits can't be negative");
const SpaceshipRampState.initial() : this(hits: 0);
const SpaceshipRampState.initial()
: this(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
);
final int hits;
final SpaceshipRampArrowSpriteState arrowState;
SpaceshipRampState copyWith({
int? hits,
SpaceshipRampArrowSpriteState? arrowState,
}) {
return SpaceshipRampState(
hits: hits ?? this.hits,
arrowState: arrowState ?? this.arrowState,
);
}
@override
List<Object?> get props => [hits];
List<Object?> get props => [hits, arrowState];
}

@ -17,8 +17,15 @@ class SpaceshipRamp extends Component {
/// {@macro spaceship_ramp}
SpaceshipRamp({
Iterable<Component>? children,
}) : bloc = SpaceshipRampCubit(),
super(
}) : this._(
children: children,
bloc: SpaceshipRampCubit(),
);
SpaceshipRamp._({
Iterable<Component>? children,
required this.bloc,
}) : super(
children: [
// TODO(ruimiguel): refactor RampSensor and RampOpening to be in
// only one sensor.
@ -46,7 +53,9 @@ class SpaceshipRamp extends Component {
_SpaceshipRampForegroundRailing(),
_SpaceshipRampBase()..initialPosition = Vector2(1.7, -20),
_SpaceshipRampBackgroundRailingSpriteComponent(),
_SpaceshipRampArrowSpriteComponent(),
_SpaceshipRampArrowSpriteComponent(
current: bloc.state.arrowState,
),
...?children,
],
);
@ -69,34 +78,6 @@ class SpaceshipRamp extends Component {
bloc.close();
super.onRemove();
}
/// Forwards the sprite to the next [SpaceshipRampArrowSpriteState].
///
/// If the current state is the last one it cycles back to the initial state.
void progress() =>
firstChild<_SpaceshipRampArrowSpriteComponent>()?.progress();
}
/// Indicates the state of the arrow on the [SpaceshipRamp].
@visibleForTesting
enum SpaceshipRampArrowSpriteState {
/// Arrow with no dashes lit up.
inactive,
/// Arrow with 1 light lit up.
active1,
/// Arrow with 2 lights lit up.
active2,
/// Arrow with 3 lights lit up.
active3,
/// Arrow with 4 lights lit up.
active4,
/// Arrow with all 5 lights lit up.
active5,
}
extension on SpaceshipRampArrowSpriteState {
@ -116,11 +97,6 @@ extension on SpaceshipRampArrowSpriteState {
return Assets.images.android.ramp.arrow.active5.keyName;
}
}
SpaceshipRampArrowSpriteState get next {
return SpaceshipRampArrowSpriteState
.values[(index + 1) % SpaceshipRampArrowSpriteState.values.length];
}
}
class _SpaceshipRampBackground extends BodyComponent
@ -228,22 +204,23 @@ class _SpaceshipRampBackgroundRampSpriteComponent extends SpriteComponent
/// {@endtemplate}
class _SpaceshipRampArrowSpriteComponent
extends SpriteGroupComponent<SpaceshipRampArrowSpriteState>
with HasGameRef, ZIndex {
with HasGameRef, ParentIsA<SpaceshipRamp>, ZIndex {
/// {@macro spaceship_ramp_arrow_sprite_component}
_SpaceshipRampArrowSpriteComponent()
: super(
_SpaceshipRampArrowSpriteComponent({
required SpaceshipRampArrowSpriteState current,
}) : super(
anchor: Anchor.center,
position: Vector2(-3.9, -56.5),
current: current,
) {
zIndex = ZIndexes.spaceshipRampArrow;
}
/// Changes arrow image to the next [Sprite].
void progress() => current = current?.next;
@override
Future<void> onLoad() async {
await super.onLoad();
parent.bloc.stream.listen((state) => current = state.arrowState);
final sprites = <SpaceshipRampArrowSpriteState, Sprite>{};
this.sprites = sprites;
for (final spriteState in SpaceshipRampArrowSpriteState.values) {

@ -54,7 +54,7 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents {
) {
if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.space) {
_spaceshipRamp.progress();
//_spaceshipRamp.progress();
return KeyEventResult.handled;
}

@ -8,18 +8,90 @@ void main() {
group('SpaceshipRampCubit', () {
group('onBallInside', () {
blocTest<SpaceshipRampCubit, SpaceshipRampState>(
'emits hits incremented',
'emits hits incremented and arrow goes to the next value',
build: SpaceshipRampCubit.new,
act: (bloc) => bloc
..onBallInside()
..onBallInside()
..onBallInside(),
expect: () => [
SpaceshipRampState(hits: 1),
SpaceshipRampState(hits: 2),
SpaceshipRampState(hits: 3),
SpaceshipRampState(
hits: 1,
arrowState: SpaceshipRampArrowSpriteState.active1,
),
SpaceshipRampState(
hits: 2,
arrowState: SpaceshipRampArrowSpriteState.active2,
),
SpaceshipRampState(
hits: 3,
arrowState: SpaceshipRampArrowSpriteState.active3,
),
],
);
group('arrowState', () {
blocTest<SpaceshipRampCubit, SpaceshipRampState>(
'goes to the next value while less than max',
build: SpaceshipRampCubit.new,
act: (bloc) => bloc
..onBallInside()
..onBallInside()
..onBallInside()
..onBallInside()
..onBallInside(),
expect: () => [
isA<SpaceshipRampState>()
..having(
(state) => state.arrowState,
'arrowState',
SpaceshipRampArrowSpriteState.active1,
),
isA<SpaceshipRampState>()
..having(
(state) => state.arrowState,
'arrowState',
SpaceshipRampArrowSpriteState.active2,
),
isA<SpaceshipRampState>()
..having(
(state) => state.arrowState,
'arrowState',
SpaceshipRampArrowSpriteState.active3,
),
isA<SpaceshipRampState>()
..having(
(state) => state.arrowState,
'arrowState',
SpaceshipRampArrowSpriteState.active4,
),
isA<SpaceshipRampState>()
..having(
(state) => state.arrowState,
'arrowState',
SpaceshipRampArrowSpriteState.active5,
),
],
);
blocTest<SpaceshipRampCubit, SpaceshipRampState>(
'goes to the initial value when is max',
build: SpaceshipRampCubit.new,
seed: () => SpaceshipRampState(
hits: 5,
arrowState: SpaceshipRampArrowSpriteState.active5,
),
act: (bloc) => bloc..onBallInside(),
expect: () => [
isA<SpaceshipRampState>()
..having(
(state) => state.arrowState,
'arrowState',
SpaceshipRampArrowSpriteState.inactive,
),
],
);
});
});
});
}

@ -9,10 +9,12 @@ void main() {
expect(
SpaceshipRampState(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
),
equals(
SpaceshipRampState(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
),
),
);
@ -23,6 +25,7 @@ void main() {
expect(
SpaceshipRampState(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
),
isNotNull,
);
@ -36,6 +39,7 @@ void main() {
expect(
() => SpaceshipRampState(
hits: -1,
arrowState: SpaceshipRampArrowSpriteState.inactive,
),
throwsAssertionError,
);
@ -49,6 +53,7 @@ void main() {
() {
const rampState = SpaceshipRampState(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
);
expect(
() => rampState.copyWith(hits: rampState.hits - 1),
@ -63,6 +68,7 @@ void main() {
() {
const rampState = SpaceshipRampState(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
);
expect(
rampState.copyWith(),
@ -77,15 +83,18 @@ void main() {
() {
const rampState = SpaceshipRampState(
hits: 0,
arrowState: SpaceshipRampArrowSpriteState.inactive,
);
final otherRampState = SpaceshipRampState(
hits: rampState.hits + 1,
arrowState: SpaceshipRampArrowSpriteState.active1,
);
expect(rampState, isNot(equals(otherRampState)));
expect(
rampState.copyWith(
hits: rampState.hits + 1,
arrowState: SpaceshipRampArrowSpriteState.active1,
),
equals(otherRampState),
);

@ -46,14 +46,14 @@ void main() {
'inactive sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final component = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [component]);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
await tester.pump();
expect(
component.children.whereType<SpriteGroupComponent>().first.current,
ramp.children.whereType<SpriteGroupComponent>().first.current,
SpaceshipRampArrowSpriteState.inactive,
);
@ -71,15 +71,15 @@ void main() {
'active1 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final component = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [component]);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
component.progress();
ramp.bloc.onBallInside();
await tester.pump();
expect(
component.children.whereType<SpriteGroupComponent>().first.current,
ramp.children.whereType<SpriteGroupComponent>().first.current,
SpaceshipRampArrowSpriteState.active1,
);
@ -97,17 +97,18 @@ void main() {
'active2 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final component = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [component]);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
component
..progress()
..progress();
ramp.bloc
..onBallInside()
..onBallInside();
await tester.pump();
expect(
component.children.whereType<SpriteGroupComponent>().first.current,
ramp.children.whereType<SpriteGroupComponent>().first.current,
SpaceshipRampArrowSpriteState.active2,
);
@ -125,18 +126,19 @@ void main() {
'active3 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final component = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [component]);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
component
..progress()
..progress()
..progress();
ramp.bloc
..onBallInside()
..onBallInside()
..onBallInside();
await tester.pump();
expect(
component.children.whereType<SpriteGroupComponent>().first.current,
ramp.children.whereType<SpriteGroupComponent>().first.current,
SpaceshipRampArrowSpriteState.active3,
);
@ -154,19 +156,20 @@ void main() {
'active4 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final component = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [component]);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
component
..progress()
..progress()
..progress()
..progress();
ramp.bloc
..onBallInside()
..onBallInside()
..onBallInside()
..onBallInside();
await tester.pump();
expect(
component.children.whereType<SpriteGroupComponent>().first.current,
ramp.children.whereType<SpriteGroupComponent>().first.current,
SpaceshipRampArrowSpriteState.active4,
);
@ -184,20 +187,21 @@ void main() {
'active5 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final component = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [component]);
final ramp = SpaceshipRamp();
final canvas = ZCanvasComponent(children: [ramp]);
await game.ensureAdd(canvas);
component
..progress()
..progress()
..progress()
..progress()
..progress();
ramp.bloc
..onBallInside()
..onBallInside()
..onBallInside()
..onBallInside()
..onBallInside();
await tester.pump();
expect(
component.children.whereType<SpriteGroupComponent>().first.current,
ramp.children.whereType<SpriteGroupComponent>().first.current,
SpaceshipRampArrowSpriteState.active5,
);

Loading…
Cancel
Save