refactor: changed bloc events names for multiplier

pull/213/head
RuiAlonso 3 years ago
commit d0590e8f56

@ -11,9 +11,9 @@ class GameBloc extends Bloc<GameEvent, GameState> {
GameBloc() : super(const GameState.initial()) { GameBloc() : super(const GameState.initial()) {
on<BallLost>(_onBallLost); on<BallLost>(_onBallLost);
on<Scored>(_onScored); on<Scored>(_onScored);
on<IncreasedMultiplier>(_onIncreasedMultiplier); on<MultiplierIncreased>(_onIncreasedMultiplier);
on<AppliedMultiplier>(_onAppliedMultiplier); on<MultiplierApplied>(_onAppliedMultiplier);
on<ResetMultiplier>(_onResetMultiplier); on<MultiplierReset>(_onResetMultiplier);
on<BonusActivated>(_onBonusActivated); on<BonusActivated>(_onBonusActivated);
on<SparkyTurboChargeActivated>(_onSparkyTurboChargeActivated); on<SparkyTurboChargeActivated>(_onSparkyTurboChargeActivated);
} }
@ -30,19 +30,19 @@ class GameBloc extends Bloc<GameEvent, GameState> {
} }
} }
void _onIncreasedMultiplier(IncreasedMultiplier event, Emitter emit) { void _onIncreasedMultiplier(MultiplierIncreased event, Emitter emit) {
if (!state.isGameOver) { if (!state.isGameOver) {
emit(state.copyWith(multiplier: state.multiplier + event.increase)); emit(state.copyWith(multiplier: state.multiplier + event.increase));
} }
} }
void _onAppliedMultiplier(AppliedMultiplier event, Emitter emit) { void _onAppliedMultiplier(MultiplierApplied event, Emitter emit) {
if (!state.isGameOver) { if (!state.isGameOver) {
emit(state.copyWith(score: state.score * state.multiplier)); emit(state.copyWith(score: state.score * state.multiplier));
} }
} }
void _onResetMultiplier(ResetMultiplier event, Emitter emit) { void _onResetMultiplier(MultiplierReset event, Emitter emit) {
if (!state.isGameOver) { if (!state.isGameOver) {
emit(state.copyWith(multiplier: 1)); emit(state.copyWith(multiplier: 1));
} }

@ -49,12 +49,12 @@ class SparkyTurboChargeActivated extends GameEvent {
List<Object?> get props => []; List<Object?> get props => [];
} }
/// {@template increased_multiplier_game_event} /// {@template multiplier_increased_game_event}
/// Event added when multiplier is being increased. /// Event added when multiplier is being increased.
/// {@endtemplate} /// {@endtemplate}
class IncreasedMultiplier extends GameEvent { class MultiplierIncreased extends GameEvent {
/// {@macro increased_multiplier_game_event} /// {@macro multiplier_increased_game_event}
const IncreasedMultiplier({ const MultiplierIncreased({
required this.increase, required this.increase,
}) : assert(increase > 0, 'Increase must be greater than 0'); }) : assert(increase > 0, 'Increase must be greater than 0');
@ -64,23 +64,23 @@ class IncreasedMultiplier extends GameEvent {
List<Object?> get props => [increase]; List<Object?> get props => [increase];
} }
/// {@template applied_multiplier_game_event} /// {@template multiplier_applied_game_event}
/// Event added when multiplier is applied to score. /// Event added when multiplier is applied to score.
/// {@endtemplate} /// {@endtemplate}
class AppliedMultiplier extends GameEvent { class MultiplierApplied extends GameEvent {
/// {@macro applied_multiplier_game_event} /// {@macro multiplier_applied_game_event}
const AppliedMultiplier(); const MultiplierApplied();
@override @override
List<Object?> get props => []; List<Object?> get props => [];
} }
/// {@template reset_multiplier_game_event} /// {@template multiplier_reset_game_event}
/// Event added when multiplier is reset. /// Event added when multiplier is reset.
/// {@endtemplate} /// {@endtemplate}
class ResetMultiplier extends GameEvent { class MultiplierReset extends GameEvent {
/// {@macro reset_multiplier_game_event} /// {@macro multiplier_reset_game_event}
const ResetMultiplier(); const MultiplierReset();
@override @override
List<Object?> get props => []; List<Object?> get props => [];

@ -9,7 +9,6 @@ export 'flutter_forest.dart';
export 'game_flow_controller.dart'; export 'game_flow_controller.dart';
export 'google_word.dart'; export 'google_word.dart';
export 'launcher.dart'; export 'launcher.dart';
export 'score_effect_controller.dart';
export 'score_points.dart'; export 'score_points.dart';
export 'sparky_fire_zone.dart'; export 'sparky_fire_zone.dart';
export 'wall.dart'; export 'wall.dart';

@ -1,45 +0,0 @@
import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template score_effect_controller}
/// A [ComponentController] responsible for adding [ScoreText]s
/// on the game screen when the user earns points.
/// {@endtemplate}
class ScoreEffectController extends ComponentController<PinballGame>
with BlocComponent<GameBloc, GameState> {
/// {@macro score_effect_controller}
ScoreEffectController(PinballGame component) : super(component);
int _lastScore = 0;
final _random = Random();
double _noise() {
return _random.nextDouble() * 5 * (_random.nextBool() ? -1 : 1);
}
@override
bool listenWhen(GameState? previousState, GameState newState) {
return previousState?.score != newState.score;
}
@override
void onNewState(GameState state) {
final newScore = state.score - _lastScore;
_lastScore = state.score;
component.add(
ScoreText(
text: newScore.toString(),
position: Vector2(
_noise(),
_noise() + (BoardDimensions.bounds.topCenter.dy + 10),
),
),
);
}
}

@ -30,11 +30,18 @@ class BallScorePointsCallback extends ContactCallback<Ball, ScorePoints> {
@override @override
void begin( void begin(
Ball _, Ball ball,
ScorePoints scorePoints, ScorePoints scorePoints,
Contact __, Contact _,
) { ) {
_gameRef.read<GameBloc>().add(Scored(points: scorePoints.points)); _gameRef.read<GameBloc>().add(Scored(points: scorePoints.points));
_gameRef.audio.score(); _gameRef.audio.score();
_gameRef.add(
ScoreText(
text: scorePoints.points.toString(),
position: ball.body.position,
),
);
} }
} }

@ -41,13 +41,30 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.boundary.outer.keyName), images.load(components.Assets.images.boundary.outer.keyName),
images.load(components.Assets.images.spaceship.saucer.keyName), images.load(components.Assets.images.spaceship.saucer.keyName),
images.load(components.Assets.images.spaceship.bridge.keyName), images.load(components.Assets.images.spaceship.bridge.keyName),
images.load(components.Assets.images.spaceship.ramp.main.keyName),
images.load(components.Assets.images.spaceship.ramp.boardOpening.keyName), images.load(components.Assets.images.spaceship.ramp.boardOpening.keyName),
images.load(
components.Assets.images.spaceship.ramp.railingForeground.keyName,
),
images.load( images.load(
components.Assets.images.spaceship.ramp.railingBackground.keyName, components.Assets.images.spaceship.ramp.railingBackground.keyName,
), ),
images.load(components.Assets.images.spaceship.ramp.main.keyName),
images
.load(components.Assets.images.spaceship.ramp.arrow.inactive.keyName),
images.load( images.load(
components.Assets.images.spaceship.ramp.railingForeground.keyName, components.Assets.images.spaceship.ramp.arrow.active1.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active2.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active3.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active4.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active5.keyName,
), ),
images.load(components.Assets.images.spaceship.rail.main.keyName), images.load(components.Assets.images.spaceship.rail.main.keyName),
images.load(components.Assets.images.spaceship.rail.foreground.keyName), images.load(components.Assets.images.spaceship.rail.foreground.keyName),

@ -42,7 +42,6 @@ class PinballGame extends Forge2DGame
Future<void> onLoad() async { Future<void> onLoad() async {
_addContactCallbacks(); _addContactCallbacks();
unawaited(add(ScoreEffectController(this)));
unawaited(add(gameFlowController = GameFlowController(this))); unawaited(add(gameFlowController = GameFlowController(this)));
unawaited(add(CameraController(this))); unawaited(add(CameraController(this)));
unawaited(add(Backboard.waiting(position: Vector2(0, -88)))); unawaited(add(Backboard.waiting(position: Vector2(0, -88))));

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 19 KiB

@ -311,6 +311,9 @@ class $AssetsImagesSpaceshipRailGen {
class $AssetsImagesSpaceshipRampGen { class $AssetsImagesSpaceshipRampGen {
const $AssetsImagesSpaceshipRampGen(); const $AssetsImagesSpaceshipRampGen();
$AssetsImagesSpaceshipRampArrowGen get arrow =>
const $AssetsImagesSpaceshipRampArrowGen();
/// File path: assets/images/spaceship/ramp/board-opening.png /// File path: assets/images/spaceship/ramp/board-opening.png
AssetGenImage get boardOpening => AssetGenImage get boardOpening =>
const AssetGenImage('assets/images/spaceship/ramp/board-opening.png'); const AssetGenImage('assets/images/spaceship/ramp/board-opening.png');
@ -384,6 +387,34 @@ class $AssetsImagesDashBumperMainGen {
const AssetGenImage('assets/images/dash/bumper/main/inactive.png'); const AssetGenImage('assets/images/dash/bumper/main/inactive.png');
} }
class $AssetsImagesSpaceshipRampArrowGen {
const $AssetsImagesSpaceshipRampArrowGen();
/// File path: assets/images/spaceship/ramp/arrow/active1.png
AssetGenImage get active1 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active1.png');
/// File path: assets/images/spaceship/ramp/arrow/active2.png
AssetGenImage get active2 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active2.png');
/// File path: assets/images/spaceship/ramp/arrow/active3.png
AssetGenImage get active3 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active3.png');
/// File path: assets/images/spaceship/ramp/arrow/active4.png
AssetGenImage get active4 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active4.png');
/// File path: assets/images/spaceship/ramp/arrow/active5.png
AssetGenImage get active5 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active5.png');
/// File path: assets/images/spaceship/ramp/arrow/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/inactive.png');
}
class $AssetsImagesSparkyBumperAGen { class $AssetsImagesSparkyBumperAGen {
const $AssetsImagesSparkyBumperAGen(); const $AssetsImagesSparkyBumperAGen();

@ -101,6 +101,8 @@ abstract class RenderPriority {
static const int spaceshipRampBackgroundRailing = _above + spaceshipRamp; static const int spaceshipRampBackgroundRailing = _above + spaceshipRamp;
static const int spaceshipRampArrow = _above + spaceshipRamp;
static const int spaceshipRampForegroundRailing = static const int spaceshipRampForegroundRailing =
_above + ballOnSpaceshipRamp; _above + ballOnSpaceshipRamp;

@ -4,6 +4,7 @@ import 'dart:math' as math;
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/gen/assets.gen.dart'; import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets; import 'package:pinball_components/pinball_components.dart' hide Assets;
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
@ -15,6 +16,15 @@ class SpaceshipRamp extends Forge2DBlueprint {
/// {@macro spaceship_ramp} /// {@macro spaceship_ramp}
SpaceshipRamp(); SpaceshipRamp();
/// [SpriteGroupComponent] representing the arrow that lights up.
@visibleForTesting
late final SpaceshipRampArrowSpriteComponent spaceshipRampArrow;
/// Forwards the sprite to the next [SpaceshipRampArrowSpriteState].
///
/// If the current state is the last one it cycles back to the initial state.
void progress() => spaceshipRampArrow.progress();
@override @override
void build(_) { void build(_) {
addAllContactCallback([ addAllContactCallback([
@ -23,20 +33,22 @@ class SpaceshipRamp extends Forge2DBlueprint {
final rightOpening = _SpaceshipRampOpening( final rightOpening = _SpaceshipRampOpening(
outsidePriority: RenderPriority.ballOnBoard, outsidePriority: RenderPriority.ballOnBoard,
rotation: math.pi, rotation: -5 * math.pi / 180,
) )
..initialPosition = Vector2(1.7, -19.8) ..initialPosition = Vector2(1.7, -19.12)
..layer = Layer.opening; ..layer = Layer.opening;
final leftOpening = _SpaceshipRampOpening( final leftOpening = _SpaceshipRampOpening(
outsideLayer: Layer.spaceship, outsideLayer: Layer.spaceship,
outsidePriority: RenderPriority.ballOnSpaceship, outsidePriority: RenderPriority.ballOnSpaceship,
rotation: math.pi, rotation: -5 * math.pi / 180,
) )
..initialPosition = Vector2(-13.7, -18.6) ..initialPosition = Vector2(-13.7, -19)
..layer = Layer.spaceshipEntranceRamp; ..layer = Layer.spaceshipEntranceRamp;
final spaceshipRamp = _SpaceshipRampBackground(); final spaceshipRamp = _SpaceshipRampBackground();
spaceshipRampArrow = SpaceshipRampArrowSpriteComponent();
final spaceshipRampBoardOpeningSprite = final spaceshipRampBoardOpeningSprite =
_SpaceshipRampBoardOpeningSpriteComponent() _SpaceshipRampBoardOpeningSpriteComponent()
..position = Vector2(3.4, -39.5); ..position = Vector2(3.4, -39.5);
@ -52,15 +64,69 @@ class SpaceshipRamp extends Forge2DBlueprint {
baseRight, baseRight,
_SpaceshipRampBackgroundRailingSpriteComponent(), _SpaceshipRampBackgroundRailingSpriteComponent(),
spaceshipRamp, spaceshipRamp,
spaceshipRampArrow,
spaceshipRampForegroundRailing, spaceshipRampForegroundRailing,
]); ]);
} }
} }
/// 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 {
String get path {
switch (this) {
case SpaceshipRampArrowSpriteState.inactive:
return Assets.images.spaceship.ramp.arrow.inactive.keyName;
case SpaceshipRampArrowSpriteState.active1:
return Assets.images.spaceship.ramp.arrow.active1.keyName;
case SpaceshipRampArrowSpriteState.active2:
return Assets.images.spaceship.ramp.arrow.active2.keyName;
case SpaceshipRampArrowSpriteState.active3:
return Assets.images.spaceship.ramp.arrow.active3.keyName;
case SpaceshipRampArrowSpriteState.active4:
return Assets.images.spaceship.ramp.arrow.active4.keyName;
case SpaceshipRampArrowSpriteState.active5:
return Assets.images.spaceship.ramp.arrow.active5.keyName;
}
}
SpaceshipRampArrowSpriteState get next {
return SpaceshipRampArrowSpriteState
.values[(index + 1) % SpaceshipRampArrowSpriteState.values.length];
}
}
class _SpaceshipRampBackground extends BodyComponent class _SpaceshipRampBackground extends BodyComponent
with InitialPosition, Layered { with InitialPosition, Layered {
_SpaceshipRampBackground() : super(priority: RenderPriority.spaceshipRamp) { _SpaceshipRampBackground()
: super(
priority: RenderPriority.spaceshipRamp,
children: [
_SpaceshipRampBackgroundRampSpriteComponent(),
],
) {
layer = Layer.spaceshipEntranceRamp; layer = Layer.spaceshipEntranceRamp;
renderBody = false;
} }
/// Width between walls of the ramp. /// Width between walls of the ramp.
@ -112,30 +178,26 @@ class _SpaceshipRampBackground extends BodyComponent
return body; return body;
} }
@override
Future<void> onLoad() async {
await super.onLoad();
renderBody = false;
await add(_SpaceshipRampBackgroundRampSpriteComponent());
}
} }
class _SpaceshipRampBackgroundRailingSpriteComponent extends SpriteComponent class _SpaceshipRampBackgroundRailingSpriteComponent extends SpriteComponent
with HasGameRef { with HasGameRef {
_SpaceshipRampBackgroundRailingSpriteComponent() _SpaceshipRampBackgroundRailingSpriteComponent()
: super(priority: RenderPriority.spaceshipRampBackgroundRailing); : super(
anchor: Anchor.center,
position: Vector2(-11.7, -54.3),
priority: RenderPriority.spaceshipRampBackgroundRailing,
);
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.railingBackground.keyName, Assets.images.spaceship.ramp.railingBackground.keyName,
),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-11.7, -54.3);
} }
} }
@ -144,13 +206,50 @@ class _SpaceshipRampBackgroundRampSpriteComponent extends SpriteComponent
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.main.keyName, Assets.images.spaceship.ramp.main.keyName,
),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
anchor = Anchor.center; anchor = Anchor.center;
position = Vector2(-11.7, -53.6); position = Vector2(-10.7, -53.6);
}
}
/// {@template spaceship_ramp_arrow_sprite_component}
/// An arrow inside [SpaceshipRamp].
///
/// Lights up a each dash whenever a [Ball] gets into [SpaceshipRamp].
/// {@endtemplate}
class SpaceshipRampArrowSpriteComponent
extends SpriteGroupComponent<SpaceshipRampArrowSpriteState>
with HasGameRef {
/// {@macro spaceship_ramp_arrow_sprite_component}
SpaceshipRampArrowSpriteComponent()
: super(
anchor: Anchor.center,
position: Vector2(-3.9, -56.5),
priority: RenderPriority.spaceshipRampArrow,
);
/// Changes arrow image to the next [Sprite].
void progress() => current = current?.next;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprites = <SpaceshipRampArrowSpriteState, Sprite>{};
this.sprites = sprites;
for (final spriteState in SpaceshipRampArrowSpriteState.values) {
sprites[spriteState] = Sprite(
gameRef.images.fromCache(spriteState.path),
);
}
current = SpaceshipRampArrowSpriteState.inactive;
size = sprites[current]!.originalSize / 10;
} }
} }
@ -159,8 +258,10 @@ class _SpaceshipRampBoardOpeningSpriteComponent extends SpriteComponent
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.boardOpening.keyName, Assets.images.spaceship.ramp.boardOpening.keyName,
),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
@ -231,16 +332,22 @@ class _SpaceshipRampForegroundRailing extends BodyComponent
class _SpaceshipRampForegroundRailingSpriteComponent extends SpriteComponent class _SpaceshipRampForegroundRailingSpriteComponent extends SpriteComponent
with HasGameRef { with HasGameRef {
_SpaceshipRampForegroundRailingSpriteComponent()
: super(
anchor: Anchor.center,
position: Vector2(-12.3, -52.5),
);
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.railingForeground.keyName, Assets.images.spaceship.ramp.railingForeground.keyName,
),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-12.3, -52.5);
} }
} }

@ -52,6 +52,7 @@ flutter:
- assets/images/spaceship/ - assets/images/spaceship/
- assets/images/spaceship/rail/ - assets/images/spaceship/rail/
- assets/images/spaceship/ramp/ - assets/images/spaceship/ramp/
- assets/images/spaceship/ramp/arrow/
- assets/images/chrome_dino/ - assets/images/chrome_dino/
- assets/images/kicker/ - assets/images/kicker/
- assets/images/plunger/ - assets/images/plunger/

@ -2,11 +2,12 @@ import 'dart:async';
import 'package:flame/input.dart'; import 'package:flame/input.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart'; import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SpaceshipRampGame extends BasicBallGame { class SpaceshipRampGame extends BasicBallGame with KeyboardEvents {
SpaceshipRampGame() SpaceshipRampGame()
: super( : super(
color: Colors.blue, color: Colors.blue,
@ -19,13 +20,45 @@ class SpaceshipRampGame extends BasicBallGame {
- Activate the "trace" parameter to overlay the body. - Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a ball into the game. - Tap anywhere on the screen to spawn a ball into the game.
- Press space to progress arrow sprites.
'''; ''';
late final SpaceshipRamp _spaceshipRamp;
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
await addFromBlueprint(SpaceshipRamp());
await images.loadAll([
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
]);
_spaceshipRamp = SpaceshipRamp();
await addFromBlueprint(_spaceshipRamp);
camera.followVector2(Vector2(-12, -50)); camera.followVector2(Vector2(-12, -50));
await traceAllBodies(); await traceAllBodies();
} }
@override
KeyEventResult onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.space) {
_spaceshipRamp.progress();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

@ -1,5 +1,6 @@
// ignore_for_file: cascade_invocations // ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -9,22 +10,197 @@ import 'package:pinball_flame/pinball_flame.dart';
import '../../helpers/helpers.dart'; import '../../helpers/helpers.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
group('SpaceshipRamp', () { group('SpaceshipRamp', () {
final tester = FlameTester(TestGame.new); flameTester.test(
'loads correctly',
(game) async {
final spaceshipRamp = SpaceshipRamp();
await game.ensureAdd(spaceshipRamp);
expect(game.contains(spaceshipRamp), isTrue);
},
);
group('renders correctly', () {
final centerForSpaceshipRamp = Vector2(-13, -55);
flameTester.testGameWidget(
'inactive sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.inactive,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/inactive.png'),
);
},
);
flameTester.testGameWidget(
'active1 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp.progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active1,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active1.png'),
);
},
);
flameTester.testGameWidget(
'active2 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active2,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active2.png'),
);
},
);
tester.testGameWidget( flameTester.testGameWidget(
'renders correctly', 'active3 sprite',
setUp: (game, tester) async { setUp: (game, tester) async {
await game.addFromBlueprint(SpaceshipRamp()); await game.images.loadAll(assets);
game.camera.followVector2(Vector2(-13, -50)); final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready(); await game.ready();
spaceshipRamp
..progress()
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active3,
);
game.camera.followVector2(centerForSpaceshipRamp);
}, },
verify: (game, tester) async { verify: (game, tester) async {
await expectLater( await expectLater(
find.byGame<TestGame>(), find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship-ramp.png'), matchesGoldenFile('golden/spaceship_ramp/active3.png'),
); );
}, },
); );
flameTester.testGameWidget(
'active4 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress()
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active4,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active4.png'),
);
},
);
flameTester.testGameWidget(
'active5 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress()
..progress()
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active5,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active5.png'),
);
},
);
});
}); });
} }

@ -85,14 +85,14 @@ void main() {
); );
}); });
group('IncreasedMultiplier', () { group('MultiplierIncreased', () {
blocTest<GameBloc, GameState>( blocTest<GameBloc, GameState>(
'increases multiplier ' 'increases multiplier '
'when game is not over', 'when game is not over',
build: GameBloc.new, build: GameBloc.new,
act: (bloc) => bloc act: (bloc) => bloc
..add(const IncreasedMultiplier(increase: 1)) ..add(const MultiplierIncreased(increase: 1))
..add(const IncreasedMultiplier(increase: 1)), ..add(const MultiplierIncreased(increase: 1)),
expect: () => [ expect: () => [
const GameState( const GameState(
score: 0, score: 0,
@ -117,7 +117,7 @@ void main() {
for (var i = 0; i < bloc.state.balls; i++) { for (var i = 0; i < bloc.state.balls; i++) {
bloc.add(const BallLost()); bloc.add(const BallLost());
} }
bloc.add(const IncreasedMultiplier(increase: 1)); bloc.add(const MultiplierIncreased(increase: 1));
}, },
expect: () => [ expect: () => [
const GameState( const GameState(
@ -142,7 +142,7 @@ void main() {
); );
}); });
group('AppliedMultiplier', () { group('MultiplierApplied', () {
blocTest<GameBloc, GameState>( blocTest<GameBloc, GameState>(
'apply multiplier to score', 'apply multiplier to score',
build: GameBloc.new, build: GameBloc.new,
@ -153,7 +153,7 @@ void main() {
bonusHistory: [], bonusHistory: [],
), ),
act: (bloc) { act: (bloc) {
bloc.add(const AppliedMultiplier()); bloc.add(const MultiplierApplied());
}, },
expect: () => [ expect: () => [
const GameState( const GameState(
@ -166,7 +166,7 @@ void main() {
); );
}); });
group('ResetMultiplier', () { group('MultiplierReset', () {
blocTest<GameBloc, GameState>( blocTest<GameBloc, GameState>(
'resets multiplier', 'resets multiplier',
build: GameBloc.new, build: GameBloc.new,
@ -177,7 +177,7 @@ void main() {
bonusHistory: [], bonusHistory: [],
), ),
act: (bloc) { act: (bloc) {
bloc.add(const ResetMultiplier()); bloc.add(const MultiplierReset());
}, },
expect: () => [ expect: () => [
const GameState( const GameState(

@ -41,51 +41,51 @@ void main() {
}); });
}); });
group('IncreasedMultiplier', () { group('MultiplierIncreased', () {
test('can be instantiated', () { test('can be instantiated', () {
expect(const IncreasedMultiplier(increase: 1), isNotNull); expect(const MultiplierIncreased(increase: 1), isNotNull);
}); });
test('supports value equality', () { test('supports value equality', () {
expect( expect(
IncreasedMultiplier(increase: 1), MultiplierIncreased(increase: 1),
equals(const IncreasedMultiplier(increase: 1)), equals(const MultiplierIncreased(increase: 1)),
); );
expect( expect(
const IncreasedMultiplier(increase: 1), const MultiplierIncreased(increase: 1),
isNot(equals(const IncreasedMultiplier(increase: 2))), isNot(equals(const MultiplierIncreased(increase: 2))),
); );
}); });
test( test(
'throws AssertionError ' 'throws AssertionError '
'when increase is smaller than 1', () { 'when increase is smaller than 1', () {
expect(() => IncreasedMultiplier(increase: 0), throwsAssertionError); expect(() => MultiplierIncreased(increase: 0), throwsAssertionError);
}); });
}); });
group('AppliedMultiplier', () { group('MultiplierApplied', () {
test('can be instantiated', () { test('can be instantiated', () {
expect(const AppliedMultiplier(), isNotNull); expect(const MultiplierApplied(), isNotNull);
}); });
test('supports value equality', () { test('supports value equality', () {
expect( expect(
AppliedMultiplier(), MultiplierApplied(),
equals(const AppliedMultiplier()), equals(const MultiplierApplied()),
); );
}); });
}); });
group('ResetMultiplier', () { group('MultiplierReset', () {
test('can be instantiated', () { test('can be instantiated', () {
expect(const ResetMultiplier(), isNotNull); expect(const MultiplierReset(), isNotNull);
}); });
test('supports value equality', () { test('supports value equality', () {
expect( expect(
ResetMultiplier(), MultiplierReset(),
equals(const ResetMultiplier()), equals(const MultiplierReset()),
); );
}); });
}); });

@ -1,110 +0,0 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
group('ScoreEffectController', () {
late ScoreEffectController controller;
late PinballGame game;
setUpAll(() {
registerFallbackValue(Component());
});
setUp(() {
game = MockPinballGame();
when(() => game.add(any())).thenAnswer((_) async {});
controller = ScoreEffectController(game);
});
group('listenWhen', () {
test('returns true when the user has earned points', () {
const previous = GameState.initial();
const current = GameState(
score: 10,
multiplier: 1,
balls: 3,
bonusHistory: [],
);
expect(controller.listenWhen(previous, current), isTrue);
});
test(
'returns true when the user has earned points and there was no '
'previous state',
() {
const current = GameState(
score: 10,
multiplier: 1,
balls: 3,
bonusHistory: [],
);
expect(controller.listenWhen(null, current), isTrue);
},
);
test(
'returns false when no points were earned',
() {
const current = GameState.initial();
const previous = GameState.initial();
expect(controller.listenWhen(previous, current), isFalse);
},
);
});
group('onNewState', () {
test(
'adds a ScoreText with the correct score for the '
'first time',
() {
const state = GameState(
score: 10,
multiplier: 1,
balls: 3,
bonusHistory: [],
);
controller.onNewState(state);
final effect =
verify(() => game.add(captureAny())).captured.first as ScoreText;
expect(effect.text, equals('10'));
},
);
test('adds a ScoreTextEffect with the correct score', () {
controller.onNewState(
const GameState(
score: 10,
multiplier: 1,
balls: 3,
bonusHistory: [],
),
);
controller.onNewState(
const GameState(
score: 14,
multiplier: 1,
balls: 3,
bonusHistory: [],
),
);
final effect =
verify(() => game.add(captureAny())).captured.last as ScoreText;
expect(effect.text, equals('4'));
});
});
});
}

@ -28,9 +28,13 @@ void main() {
setUp(() { setUp(() {
game = MockPinballGame(); game = MockPinballGame();
bloc = MockGameBloc(); bloc = MockGameBloc();
ball = MockBall();
audio = MockPinballAudio(); audio = MockPinballAudio();
fakeScorePoints = FakeScorePoints(); fakeScorePoints = FakeScorePoints();
ball = MockBall();
final ballBody = MockBody();
when(() => ball.body).thenReturn(ballBody);
when(() => ballBody.position).thenReturn(Vector2.all(4));
}); });
setUpAll(() { setUpAll(() {
@ -73,6 +77,29 @@ void main() {
verify(audio.score).called(1); verify(audio.score).called(1);
}, },
); );
test(
"adds a ScoreText component at Ball's position",
() {
when(game.read<GameBloc>).thenReturn(bloc);
when(() => game.audio).thenReturn(audio);
BallScorePointsCallback(game).begin(
ball,
fakeScorePoints,
FakeContact(),
);
verify(
() => game.add(
ScoreText(
text: fakeScorePoints.points.toString(),
position: ball.body.position,
),
),
).called(1);
},
);
}); });
}); });
} }

@ -33,6 +33,16 @@ void main() {
Assets.images.sparky.bumper.b.inactive.keyName, Assets.images.sparky.bumper.b.inactive.keyName,
Assets.images.sparky.bumper.c.active.keyName, Assets.images.sparky.bumper.c.active.keyName,
Assets.images.sparky.bumper.c.inactive.keyName, Assets.images.sparky.bumper.c.inactive.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
]; ];
final flameTester = FlameTester(() => PinballTestGame(assets)); final flameTester = FlameTester(() => PinballTestGame(assets));
final debugModeFlameTester = FlameTester(() => DebugPinballTestGame(assets)); final debugModeFlameTester = FlameTester(() => DebugPinballTestGame(assets));

Loading…
Cancel
Save