mirror of https://github.com/flutter/pinball.git
feat: migration to new `ContactCallbacks` (#234)
* feat: migrated to new ContactCallbacks * refactor: moved renderBody to super call * feat: defined AlienBumper behaviours * feat: included ParentIsA mixin * refactor: modified ContactCallbacksGroup * feat: resolved missing ContactCallbacks with Behaviors * refactor: removed unused ParentIsA * refactor: moved tests * fix: invalid export * refactor: renamed behaviours * test: tested pinball_components * refactor: removed "Behaviour" typo * docs: included TODO comment for generics * docs: included flame_bloc TODO comments * refactor: renamed ContacCallbacksGroup variable * docs: included doc comments where possible * docs: rephrased ContactBehaviour doc comment * test: included ContactBehavior tests * feat: implemented FlutterForestBonusBehavior * refactor: fixed analyser warnings * test: tested DashNestBumper * refactor: moved children to last arguement * test: included closing test * refactor: used barrel files as imports * docs: included flutter_bloc TODO * test: correctly tested GoogleWordBonusBehavior * refactor: moved flutter_forest_test.dart * test: fixed AlienZone typo * feat: removed FlutterForestCubit * test: closed streams * refactor: removed optional bloc parameter * refactor: added flame_bloc TODO comment * docs: included .test constructor docs * feat: included GoogleLetter.test * test: made blink test pass * fix: renamed theme to CharacterTheme * refactor: moved timer.stop(); * refactor: renamed hasBonus to achievedBonus * refactor: ignore public_member_api_docs for cubits * test: removed beginContact group * refactor: typos correction * docs: used correct AlienBumper reference * docs: removed TODO comment from ContactBehavior subclasses * docs: includes ScoringBehavior doc * feat: adjusted FlutterForest priorities Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>pull/246/head
parent
a71afb7623
commit
2673c419b5
@ -1,60 +1,29 @@
|
|||||||
// ignore_for_file: avoid_renaming_method_parameters
|
// ignore_for_file: avoid_renaming_method_parameters
|
||||||
|
|
||||||
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/game/game.dart';
|
import 'package:pinball/game/game.dart';
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
/// {@template alien_zone}
|
/// {@template alien_zone}
|
||||||
/// Area positioned below [Spaceship] where the [Ball]
|
/// Area positioned below [Spaceship] where the [Ball]
|
||||||
/// can bounce off [AlienBumper]s.
|
/// can bounce off [AlienBumper]s.
|
||||||
///
|
|
||||||
/// When a [Ball] hits an [AlienBumper], the bumper animates.
|
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
class AlienZone extends Component with HasGameRef<PinballGame> {
|
class AlienZone extends Blueprint {
|
||||||
/// {@macro alien_zone}
|
/// {@macro alien_zone}
|
||||||
AlienZone();
|
AlienZone()
|
||||||
|
: super(
|
||||||
@override
|
components: [
|
||||||
Future<void> onLoad() async {
|
AlienBumper.a(
|
||||||
await super.onLoad();
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
gameRef.addContactCallback(AlienBumperBallContactCallback());
|
],
|
||||||
|
)..initialPosition = Vector2(-32.52, -9.1),
|
||||||
final lowerBumper = _AlienBumper.a()
|
AlienBumper.b(
|
||||||
..initialPosition = Vector2(-32.52, -9.1);
|
children: [
|
||||||
final upperBumper = _AlienBumper.b()
|
ScoringBehavior(points: 20),
|
||||||
..initialPosition = Vector2(-22.89, -17.35);
|
],
|
||||||
|
)..initialPosition = Vector2(-22.89, -17.35),
|
||||||
await addAll([
|
],
|
||||||
lowerBumper,
|
);
|
||||||
upperBumper,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(alestiago): Revisit ScorePoints logic once the FlameForge2D
|
|
||||||
// ContactCallback process is enhanced.
|
|
||||||
class _AlienBumper extends AlienBumper with ScorePoints {
|
|
||||||
_AlienBumper.a() : super.a();
|
|
||||||
|
|
||||||
_AlienBumper.b() : super.b();
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get points => 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Listens when a [Ball] bounces against an [AlienBumper].
|
|
||||||
@visibleForTesting
|
|
||||||
class AlienBumperBallContactCallback
|
|
||||||
extends ContactCallback<AlienBumper, Ball> {
|
|
||||||
@override
|
|
||||||
void begin(
|
|
||||||
AlienBumper alienBumper,
|
|
||||||
Ball _,
|
|
||||||
Contact __,
|
|
||||||
) {
|
|
||||||
alienBumper.animate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
// ignore_for_file: avoid_renaming_method_parameters
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:pinball_flame/pinball_flame.dart';
|
|
||||||
|
|
||||||
/// {@template flutter_forest}
|
|
||||||
/// Area positioned at the top right of the [Board] where the [Ball]
|
|
||||||
/// can bounce off [DashNestBumper]s.
|
|
||||||
///
|
|
||||||
/// When all [DashNestBumper]s are hit at least once, the [GameBonus.dashNest]
|
|
||||||
/// is awarded, and the [DashNestBumper.main] releases a new [Ball].
|
|
||||||
/// {@endtemplate}
|
|
||||||
class FlutterForest extends Component
|
|
||||||
with Controls<_FlutterForestController>, HasGameRef<PinballGame> {
|
|
||||||
/// {@macro flutter_forest}
|
|
||||||
FlutterForest() {
|
|
||||||
controller = _FlutterForestController(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
await super.onLoad();
|
|
||||||
gameRef.addContactCallback(_DashNestBumperBallContactCallback());
|
|
||||||
|
|
||||||
final signpost = Signpost()..initialPosition = Vector2(8.35, -58.3);
|
|
||||||
|
|
||||||
final bigNest = _DashNestBumper.main()
|
|
||||||
..initialPosition = Vector2(18.55, -59.35);
|
|
||||||
final smallLeftNest = _DashNestBumper.a()
|
|
||||||
..initialPosition = Vector2(8.95, -51.95);
|
|
||||||
final smallRightNest = _DashNestBumper.b()
|
|
||||||
..initialPosition = Vector2(23.3, -46.75);
|
|
||||||
final dashAnimatronic = DashAnimatronic()..position = Vector2(20, -66);
|
|
||||||
|
|
||||||
await addAll([
|
|
||||||
signpost,
|
|
||||||
smallLeftNest,
|
|
||||||
smallRightNest,
|
|
||||||
bigNest,
|
|
||||||
dashAnimatronic,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FlutterForestController extends ComponentController<FlutterForest>
|
|
||||||
with HasGameRef<PinballGame> {
|
|
||||||
_FlutterForestController(FlutterForest flutterForest) : super(flutterForest);
|
|
||||||
|
|
||||||
final _activatedBumpers = <DashNestBumper>{};
|
|
||||||
|
|
||||||
void activateBumper(DashNestBumper dashNestBumper) {
|
|
||||||
if (!_activatedBumpers.add(dashNestBumper)) return;
|
|
||||||
|
|
||||||
dashNestBumper.activate();
|
|
||||||
|
|
||||||
final activatedBonus = _activatedBumpers.length == 3;
|
|
||||||
if (activatedBonus) {
|
|
||||||
_addBonusBall();
|
|
||||||
|
|
||||||
gameRef.read<GameBloc>().add(const BonusActivated(GameBonus.dashNest));
|
|
||||||
_activatedBumpers
|
|
||||||
..forEach((bumper) => bumper.deactivate())
|
|
||||||
..clear();
|
|
||||||
|
|
||||||
component.firstChild<DashAnimatronic>()?.playing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _addBonusBall() async {
|
|
||||||
await gameRef.add(
|
|
||||||
ControlledBall.bonus(characterTheme: gameRef.characterTheme)
|
|
||||||
..initialPosition = Vector2(17.2, -52.7),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(alestiago): Revisit ScorePoints logic once the FlameForge2D
|
|
||||||
// ContactCallback process is enhanced.
|
|
||||||
class _DashNestBumper extends DashNestBumper with ScorePoints {
|
|
||||||
_DashNestBumper.main() : super.main();
|
|
||||||
|
|
||||||
_DashNestBumper.a() : super.a();
|
|
||||||
|
|
||||||
_DashNestBumper.b() : super.b();
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get points => 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DashNestBumperBallContactCallback
|
|
||||||
extends ContactCallback<DashNestBumper, Ball> {
|
|
||||||
@override
|
|
||||||
void begin(DashNestBumper dashNestBumper, _, __) {
|
|
||||||
final parent = dashNestBumper.parent;
|
|
||||||
if (parent is FlutterForest) {
|
|
||||||
parent.controller.activateBumper(dashNestBumper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1 @@
|
|||||||
|
export 'flutter_forest_bonus_behavior.dart';
|
@ -0,0 +1,41 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
/// When all [DashNestBumper]s are hit at least once, the [GameBonus.dashNest]
|
||||||
|
/// is awarded, and the [DashNestBumper.main] releases a new [Ball].
|
||||||
|
class FlutterForestBonusBehavior extends Component
|
||||||
|
with ParentIsA<FlutterForest>, HasGameRef<PinballGame> {
|
||||||
|
@override
|
||||||
|
void onMount() {
|
||||||
|
super.onMount();
|
||||||
|
|
||||||
|
final bumpers = parent.children.whereType<DashNestBumper>();
|
||||||
|
for (final bumper in bumpers) {
|
||||||
|
// TODO(alestiago): Refactor subscription management once the following is
|
||||||
|
// merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
bumper.bloc.stream.listen((state) {
|
||||||
|
final achievedBonus = bumpers.every(
|
||||||
|
(bumper) => bumper.bloc.state == DashNestBumperState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (achievedBonus) {
|
||||||
|
gameRef
|
||||||
|
.read<GameBloc>()
|
||||||
|
.add(const BonusActivated(GameBonus.dashNest));
|
||||||
|
gameRef.add(
|
||||||
|
ControlledBall.bonus(characterTheme: gameRef.characterTheme)
|
||||||
|
..initialPosition = Vector2(17.2, -52.7),
|
||||||
|
);
|
||||||
|
parent.firstChild<DashAnimatronic>()?.playing = true;
|
||||||
|
|
||||||
|
for (final bumper in bumpers) {
|
||||||
|
bumper.bloc.onReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// ignore_for_file: avoid_renaming_method_parameters
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball/game/components/flutter_forest/behaviors/behaviors.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// {@template flutter_forest}
|
||||||
|
/// Area positioned at the top right of the [Board] where the [Ball] can bounce
|
||||||
|
/// off [DashNestBumper]s.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class FlutterForest extends Component {
|
||||||
|
/// {@macro flutter_forest}
|
||||||
|
FlutterForest()
|
||||||
|
: super(
|
||||||
|
priority: RenderPriority.flutterForest,
|
||||||
|
children: [
|
||||||
|
Signpost(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(8.35, -58.3),
|
||||||
|
DashNestBumper.main(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(18.55, -59.35),
|
||||||
|
DashNestBumper.a(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(8.95, -51.95),
|
||||||
|
DashNestBumper.b(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(23.3, -46.75),
|
||||||
|
DashAnimatronic()..position = Vector2(20, -66),
|
||||||
|
FlutterForestBonusBehavior(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Creates a [FlutterForest] without any children.
|
||||||
|
///
|
||||||
|
/// This can be used for testing [FlutterForest]'s behaviors in isolation.
|
||||||
|
@visibleForTesting
|
||||||
|
FlutterForest.test();
|
||||||
|
}
|
@ -1,83 +0,0 @@
|
|||||||
// ignore_for_file: avoid_renaming_method_parameters
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:pinball_flame/pinball_flame.dart';
|
|
||||||
|
|
||||||
/// {@template google_word}
|
|
||||||
/// Loads all [GoogleLetter]s to compose a [GoogleWord].
|
|
||||||
/// {@endtemplate}
|
|
||||||
class GoogleWord extends Component
|
|
||||||
with HasGameRef<PinballGame>, Controls<_GoogleWordController> {
|
|
||||||
/// {@macro google_word}
|
|
||||||
GoogleWord({
|
|
||||||
required Vector2 position,
|
|
||||||
}) : _position = position {
|
|
||||||
controller = _GoogleWordController(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Vector2 _position;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
await super.onLoad();
|
|
||||||
gameRef.addContactCallback(_GoogleLetterBallContactCallback());
|
|
||||||
|
|
||||||
final offsets = [
|
|
||||||
Vector2(-12.92, 1.82),
|
|
||||||
Vector2(-8.33, -0.65),
|
|
||||||
Vector2(-2.88, -1.75),
|
|
||||||
Vector2(2.88, -1.75),
|
|
||||||
Vector2(8.33, -0.65),
|
|
||||||
Vector2(12.92, 1.82),
|
|
||||||
];
|
|
||||||
|
|
||||||
final letters = <GoogleLetter>[];
|
|
||||||
for (var index = 0; index < offsets.length; index++) {
|
|
||||||
letters.add(
|
|
||||||
GoogleLetter(index)..initialPosition = _position + offsets[index],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await addAll(letters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _GoogleWordController extends ComponentController<GoogleWord>
|
|
||||||
with HasGameRef<PinballGame> {
|
|
||||||
_GoogleWordController(GoogleWord googleWord) : super(googleWord);
|
|
||||||
|
|
||||||
final _activatedLetters = <GoogleLetter>{};
|
|
||||||
|
|
||||||
void activate(GoogleLetter googleLetter) {
|
|
||||||
if (!_activatedLetters.add(googleLetter)) return;
|
|
||||||
|
|
||||||
googleLetter.activate();
|
|
||||||
|
|
||||||
final activatedBonus = _activatedLetters.length == 6;
|
|
||||||
if (activatedBonus) {
|
|
||||||
gameRef.audio.googleBonus();
|
|
||||||
gameRef.read<GameBloc>().add(const BonusActivated(GameBonus.googleWord));
|
|
||||||
component.children.whereType<GoogleLetter>().forEach(
|
|
||||||
(letter) => letter.deactivate(),
|
|
||||||
);
|
|
||||||
_activatedLetters.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Activates a [GoogleLetter] when it contacts with a [Ball].
|
|
||||||
class _GoogleLetterBallContactCallback
|
|
||||||
extends ContactCallback<GoogleLetter, Ball> {
|
|
||||||
@override
|
|
||||||
void begin(GoogleLetter googleLetter, _, __) {
|
|
||||||
final parent = googleLetter.parent;
|
|
||||||
if (parent is GoogleWord) {
|
|
||||||
parent.controller.activate(googleLetter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1 @@
|
|||||||
|
export 'google_word_bonus_behavior.dart';
|
@ -0,0 +1,34 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
/// Adds a [GameBonus.googleWord] when all [GoogleLetter]s are activated.
|
||||||
|
class GoogleWordBonusBehavior extends Component
|
||||||
|
with HasGameRef<PinballGame>, ParentIsA<GoogleWord> {
|
||||||
|
@override
|
||||||
|
void onMount() {
|
||||||
|
super.onMount();
|
||||||
|
|
||||||
|
final googleLetters = parent.children.whereType<GoogleLetter>();
|
||||||
|
for (final letter in googleLetters) {
|
||||||
|
// TODO(alestiago): Refactor subscription management once the following is
|
||||||
|
// merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
letter.bloc.stream.listen((_) {
|
||||||
|
final achievedBonus = googleLetters
|
||||||
|
.every((letter) => letter.bloc.state == GoogleLetterState.active);
|
||||||
|
|
||||||
|
if (achievedBonus) {
|
||||||
|
gameRef.audio.googleBonus();
|
||||||
|
gameRef
|
||||||
|
.read<GameBloc>()
|
||||||
|
.add(const BonusActivated(GameBonus.googleWord));
|
||||||
|
for (final letter in googleLetters) {
|
||||||
|
letter.bloc.onReset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball/game/components/google_word/behaviors/behaviors.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// {@template google_word}
|
||||||
|
/// Loads all [GoogleLetter]s to compose a [GoogleWord].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class GoogleWord extends Component {
|
||||||
|
/// {@macro google_word}
|
||||||
|
GoogleWord({
|
||||||
|
required Vector2 position,
|
||||||
|
}) : super(
|
||||||
|
children: [
|
||||||
|
GoogleLetter(0)..initialPosition = position + Vector2(-12.92, 1.82),
|
||||||
|
GoogleLetter(1)..initialPosition = position + Vector2(-8.33, -0.65),
|
||||||
|
GoogleLetter(2)..initialPosition = position + Vector2(-2.88, -1.75),
|
||||||
|
GoogleLetter(3)..initialPosition = position + Vector2(2.88, -1.75),
|
||||||
|
GoogleLetter(4)..initialPosition = position + Vector2(8.33, -0.65),
|
||||||
|
GoogleLetter(5)..initialPosition = position + Vector2(12.92, 1.82),
|
||||||
|
GoogleWordBonusBehavior(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Creates a [GoogleWord] without any children.
|
||||||
|
///
|
||||||
|
/// This can be used for testing [GoogleWord]'s behaviors in isolation.
|
||||||
|
@visibleForTesting
|
||||||
|
GoogleWord.test();
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
// ignore_for_file: avoid_renaming_method_parameters
|
|
||||||
|
|
||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
/// {@template score_points}
|
|
||||||
/// Specifies the amount of points received on [Ball] collision.
|
|
||||||
/// {@endtemplate}
|
|
||||||
mixin ScorePoints<T extends Forge2DGame> on BodyComponent<T> {
|
|
||||||
/// {@macro score_points}
|
|
||||||
int get points;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
await super.onLoad();
|
|
||||||
body.userData = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// {@template ball_score_points_callbacks}
|
|
||||||
/// Adds points to the score when a [Ball] collides with a [BodyComponent] that
|
|
||||||
/// implements [ScorePoints].
|
|
||||||
/// {@endtemplate}
|
|
||||||
class BallScorePointsCallback extends ContactCallback<Ball, ScorePoints> {
|
|
||||||
/// {@macro ball_score_points_callbacks}
|
|
||||||
BallScorePointsCallback(PinballGame game) : _gameRef = game;
|
|
||||||
|
|
||||||
final PinballGame _gameRef;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void begin(
|
|
||||||
Ball ball,
|
|
||||||
ScorePoints scorePoints,
|
|
||||||
Contact _,
|
|
||||||
) {
|
|
||||||
_gameRef.read<GameBloc>().add(Scored(points: scorePoints.points));
|
|
||||||
_gameRef.audio.score();
|
|
||||||
|
|
||||||
_gameRef.add(
|
|
||||||
ScoreText(
|
|
||||||
text: scorePoints.points.toString(),
|
|
||||||
position: ball.body.position,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
// ignore_for_file: avoid_renaming_method_parameters
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template scoring_behavior}
|
||||||
|
/// Adds points to the score when the ball contacts the [parent].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class ScoringBehavior extends ContactBehavior with HasGameRef<PinballGame> {
|
||||||
|
/// {@macro scoring_behavior}
|
||||||
|
ScoringBehavior({
|
||||||
|
required int points,
|
||||||
|
}) : _points = points;
|
||||||
|
|
||||||
|
final int _points;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
if (other is! Ball) return;
|
||||||
|
|
||||||
|
gameRef.read<GameBloc>().add(Scored(points: _points));
|
||||||
|
gameRef.audio.score();
|
||||||
|
gameRef.add(
|
||||||
|
ScoreText(
|
||||||
|
text: _points.toString(),
|
||||||
|
position: other.body.position,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
class AlienBumperBallContactBehavior extends ContactBehavior<AlienBumper> {
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
if (other is! Ball) return;
|
||||||
|
parent.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template alien_bumper_blinking_behavior}
|
||||||
|
/// Makes a [AlienBumper] blink back to [AlienBumperState.active] when
|
||||||
|
/// [AlienBumperState.inactive].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class AlienBumperBlinkingBehavior extends TimerComponent
|
||||||
|
with ParentIsA<AlienBumper> {
|
||||||
|
/// {@macro alien_bumper_blinking_behavior}
|
||||||
|
AlienBumperBlinkingBehavior() : super(period: 0.05);
|
||||||
|
|
||||||
|
void _onNewState(AlienBumperState state) {
|
||||||
|
switch (state) {
|
||||||
|
case AlienBumperState.active:
|
||||||
|
break;
|
||||||
|
case AlienBumperState.inactive:
|
||||||
|
timer
|
||||||
|
..reset()
|
||||||
|
..start();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
timer.stop();
|
||||||
|
parent.bloc.stream.listen(_onNewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTick() {
|
||||||
|
super.onTick();
|
||||||
|
timer.stop();
|
||||||
|
parent.bloc.onBlinked();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
export 'alien_bumper_ball_contact_behavior.dart';
|
||||||
|
export 'alien_bumper_blinking_behavior.dart';
|
@ -0,0 +1,17 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
|
part 'alien_bumper_state.dart';
|
||||||
|
|
||||||
|
class AlienBumperCubit extends Cubit<AlienBumperState> {
|
||||||
|
AlienBumperCubit() : super(AlienBumperState.active);
|
||||||
|
|
||||||
|
void onBallContacted() {
|
||||||
|
emit(AlienBumperState.inactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBlinked() {
|
||||||
|
emit(AlienBumperState.active);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
part of 'alien_bumper_cubit.dart';
|
||||||
|
|
||||||
|
/// Indicates the [AlienBumperCubit]'s current state.
|
||||||
|
enum AlienBumperState {
|
||||||
|
/// A lit up bumper.
|
||||||
|
active,
|
||||||
|
|
||||||
|
/// A dimmed bumper.
|
||||||
|
inactive,
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export 'dash_nest_bumper_contact_behavior.dart';
|
@ -0,0 +1,15 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
class DashNestBumperBallContactBehavior
|
||||||
|
extends ContactBehavior<DashNestBumper> {
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
if (other is! Ball) return;
|
||||||
|
parent.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
|
part 'dash_nest_bumper_state.dart';
|
||||||
|
|
||||||
|
class DashNestBumperCubit extends Cubit<DashNestBumperState> {
|
||||||
|
DashNestBumperCubit() : super(DashNestBumperState.inactive);
|
||||||
|
|
||||||
|
/// Event added when the bumper contacts with a ball.
|
||||||
|
void onBallContacted() {
|
||||||
|
emit(DashNestBumperState.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event added when the bumper should return to its initial configuration.
|
||||||
|
void onReset() {
|
||||||
|
emit(DashNestBumperState.inactive);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
part of 'dash_nest_bumper_cubit.dart';
|
||||||
|
|
||||||
|
/// Indicates the [DashNestBumperCubit]'s current state.
|
||||||
|
enum DashNestBumperState {
|
||||||
|
/// A lit up bumper.
|
||||||
|
active,
|
||||||
|
|
||||||
|
/// A dimmed bumper.
|
||||||
|
inactive,
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export 'google_letter_ball_contact_behavior.dart';
|
@ -0,0 +1,14 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
class GoogleLetterBallContactBehavior extends ContactBehavior<GoogleLetter> {
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
if (other is! Ball) return;
|
||||||
|
parent.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
|
part 'google_letter_state.dart';
|
||||||
|
|
||||||
|
class GoogleLetterCubit extends Cubit<GoogleLetterState> {
|
||||||
|
GoogleLetterCubit() : super(GoogleLetterState.inactive);
|
||||||
|
|
||||||
|
void onBallContacted() {
|
||||||
|
emit(GoogleLetterState.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onReset() {
|
||||||
|
emit(GoogleLetterState.inactive);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
part of 'google_letter_cubit.dart';
|
||||||
|
|
||||||
|
/// Indicates the [GoogleLetterCubit]'s current state.
|
||||||
|
enum GoogleLetterState {
|
||||||
|
/// A lit up letter.
|
||||||
|
active,
|
||||||
|
|
||||||
|
/// A dimmed letter.
|
||||||
|
inactive,
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
export 'sparky_bumper_ball_contact_behavior.dart';
|
||||||
|
export 'sparky_bumper_blinking_behavior.dart';
|
@ -0,0 +1,14 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
class SparkyBumperBallContactBehavior extends ContactBehavior<SparkyBumper> {
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
if (other is! Ball) return;
|
||||||
|
parent.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template sparky_bumper_blinking_behavior}
|
||||||
|
/// Makes a [SparkyBumper] blink back to [SparkyBumperState.active] when
|
||||||
|
/// [SparkyBumperState.inactive].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class SparkyBumperBlinkingBehavior extends TimerComponent
|
||||||
|
with ParentIsA<SparkyBumper> {
|
||||||
|
/// {@macro sparky_bumper_sprite_behavior}
|
||||||
|
SparkyBumperBlinkingBehavior() : super(period: 0.05);
|
||||||
|
|
||||||
|
void _onNewState(SparkyBumperState state) {
|
||||||
|
switch (state) {
|
||||||
|
case SparkyBumperState.active:
|
||||||
|
break;
|
||||||
|
case SparkyBumperState.inactive:
|
||||||
|
timer
|
||||||
|
..reset()
|
||||||
|
..start();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
timer.stop();
|
||||||
|
parent.bloc.stream.listen(_onNewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTick() {
|
||||||
|
super.onTick();
|
||||||
|
timer.stop();
|
||||||
|
parent.bloc.onBlinked();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
|
part 'sparky_bumper_state.dart';
|
||||||
|
|
||||||
|
class SparkyBumperCubit extends Cubit<SparkyBumperState> {
|
||||||
|
SparkyBumperCubit() : super(SparkyBumperState.active);
|
||||||
|
|
||||||
|
void onBallContacted() {
|
||||||
|
emit(SparkyBumperState.inactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBlinked() {
|
||||||
|
emit(SparkyBumperState.active);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
part of 'sparky_bumper_cubit.dart';
|
||||||
|
|
||||||
|
/// Indicates the [SparkyBumperCubit]'s current state.
|
||||||
|
enum SparkyBumperState {
|
||||||
|
/// A lit up bumper.
|
||||||
|
active,
|
||||||
|
|
||||||
|
/// A dimmed bumper.
|
||||||
|
inactive,
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/alien_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final assets = [
|
||||||
|
Assets.images.alienBumper.a.active.keyName,
|
||||||
|
Assets.images.alienBumper.a.inactive.keyName,
|
||||||
|
Assets.images.alienBumper.b.active.keyName,
|
||||||
|
Assets.images.alienBumper.b.inactive.keyName,
|
||||||
|
];
|
||||||
|
final flameTester = FlameTester(() => TestGame(assets));
|
||||||
|
|
||||||
|
group('AlienBumper', () {
|
||||||
|
flameTester.test('"a" loads correctly', (game) async {
|
||||||
|
final alienBumper = AlienBumper.a();
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
expect(game.contains(alienBumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('"b" loads correctly', (game) async {
|
||||||
|
final alienBumper = AlienBumper.b();
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
expect(game.contains(alienBumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(alestiago): Consider refactoring once the following is merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
flameTester.test('closes bloc when removed', (game) async {
|
||||||
|
final bloc = MockAlienBumperCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<AlienBumperState>.empty(),
|
||||||
|
initialState: AlienBumperState.active,
|
||||||
|
);
|
||||||
|
when(bloc.close).thenAnswer((_) async {});
|
||||||
|
final alienBumper = AlienBumper.test(bloc: bloc);
|
||||||
|
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
game.remove(alienBumper);
|
||||||
|
await game.ready();
|
||||||
|
|
||||||
|
verify(bloc.close).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('adds', () {
|
||||||
|
flameTester.test('new children', (game) async {
|
||||||
|
final component = Component();
|
||||||
|
final alienBumper = AlienBumper.a(
|
||||||
|
children: [component],
|
||||||
|
);
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
expect(alienBumper.children, contains(component));
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('an AlienBumperBallContactBehavior', (game) async {
|
||||||
|
final alienBumper = AlienBumper.a();
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
expect(
|
||||||
|
alienBumper.children
|
||||||
|
.whereType<AlienBumperBallContactBehavior>()
|
||||||
|
.single,
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/alien_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
group(
|
||||||
|
'AlienBumperBallContactBehavior',
|
||||||
|
() {
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
AlienBumperBallContactBehavior(),
|
||||||
|
isA<AlienBumperBallContactBehavior>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'beginContact emits onBallContacted when contacts with a ball',
|
||||||
|
(game) async {
|
||||||
|
final behavior = AlienBumperBallContactBehavior();
|
||||||
|
final bloc = MockAlienBumperCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<AlienBumperState>.empty(),
|
||||||
|
initialState: AlienBumperState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
final alienBumper = AlienBumper.test(bloc: bloc);
|
||||||
|
await alienBumper.add(behavior);
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
|
||||||
|
behavior.beginContact(MockBall(), MockContact());
|
||||||
|
|
||||||
|
verify(alienBumper.bloc.onBallContacted).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/alien_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
group(
|
||||||
|
'AlienBumperBlinkingBehavior',
|
||||||
|
() {
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'calls onBlinked after 0.05 seconds when inactive',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
final behavior = AlienBumperBlinkingBehavior();
|
||||||
|
final bloc = MockAlienBumperCubit();
|
||||||
|
final streamController = StreamController<AlienBumperState>();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
streamController.stream,
|
||||||
|
initialState: AlienBumperState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
final alienBumper = AlienBumper.test(bloc: bloc);
|
||||||
|
await alienBumper.add(behavior);
|
||||||
|
await game.ensureAdd(alienBumper);
|
||||||
|
|
||||||
|
streamController.add(AlienBumperState.inactive);
|
||||||
|
await tester.pump();
|
||||||
|
game.update(0.05);
|
||||||
|
|
||||||
|
await streamController.close();
|
||||||
|
verify(bloc.onBlinked).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group(
|
||||||
|
'AlienBumperCubit',
|
||||||
|
() {
|
||||||
|
blocTest<AlienBumperCubit, AlienBumperState>(
|
||||||
|
'onBallContacted emits inactive',
|
||||||
|
build: AlienBumperCubit.new,
|
||||||
|
act: (bloc) => bloc.onBallContacted(),
|
||||||
|
expect: () => [AlienBumperState.inactive],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<AlienBumperCubit, AlienBumperState>(
|
||||||
|
'onBlinked emits active',
|
||||||
|
build: AlienBumperCubit.new,
|
||||||
|
act: (bloc) => bloc.onBlinked(),
|
||||||
|
expect: () => [AlienBumperState.active],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -1,61 +0,0 @@
|
|||||||
// ignore_for_file: cascade_invocations
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_test/flame_test.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
final assets = [
|
|
||||||
Assets.images.alienBumper.a.active.keyName,
|
|
||||||
Assets.images.alienBumper.a.inactive.keyName,
|
|
||||||
Assets.images.alienBumper.b.active.keyName,
|
|
||||||
Assets.images.alienBumper.b.inactive.keyName,
|
|
||||||
];
|
|
||||||
final flameTester = FlameTester(() => TestGame(assets));
|
|
||||||
|
|
||||||
group('AlienBumper', () {
|
|
||||||
flameTester.test('"a" loads correctly', (game) async {
|
|
||||||
final bumper = AlienBumper.a();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('"b" loads correctly', (game) async {
|
|
||||||
final bumper = AlienBumper.b();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('animate switches between on and off sprites',
|
|
||||||
(game) async {
|
|
||||||
final bumper = AlienBumper.a();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
final spriteGroupComponent = bumper.firstChild<SpriteGroupComponent>()!;
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(AlienBumperSpriteState.active),
|
|
||||||
);
|
|
||||||
|
|
||||||
final future = bumper.animate();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(AlienBumperSpriteState.inactive),
|
|
||||||
);
|
|
||||||
|
|
||||||
await future;
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(AlienBumperSpriteState.active),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -0,0 +1,48 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/dash_nest_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
group(
|
||||||
|
'DashNestBumperBallContactBehavior',
|
||||||
|
() {
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
DashNestBumperBallContactBehavior(),
|
||||||
|
isA<DashNestBumperBallContactBehavior>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'beginContact emits onBallContacted when contacts with a ball',
|
||||||
|
(game) async {
|
||||||
|
final behavior = DashNestBumperBallContactBehavior();
|
||||||
|
final bloc = MockDashNestBumperCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<DashNestBumperState>.empty(),
|
||||||
|
initialState: DashNestBumperState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
final dashNestBumper = DashNestBumper.test(bloc: bloc);
|
||||||
|
await dashNestBumper.add(behavior);
|
||||||
|
await game.ensureAdd(dashNestBumper);
|
||||||
|
|
||||||
|
behavior.beginContact(MockBall(), MockContact());
|
||||||
|
|
||||||
|
verify(dashNestBumper.bloc.onBallContacted).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group(
|
||||||
|
'DashNestBumperCubit',
|
||||||
|
() {
|
||||||
|
blocTest<DashNestBumperCubit, DashNestBumperState>(
|
||||||
|
'onBallContacted emits active',
|
||||||
|
build: DashNestBumperCubit.new,
|
||||||
|
act: (bloc) => bloc.onBallContacted(),
|
||||||
|
expect: () => [DashNestBumperState.active],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<DashNestBumperCubit, DashNestBumperState>(
|
||||||
|
'onReset emits inactive',
|
||||||
|
build: DashNestBumperCubit.new,
|
||||||
|
act: (bloc) => bloc.onReset(),
|
||||||
|
expect: () => [DashNestBumperState.inactive],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/dash_nest_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group('DashNestBumper', () {
|
||||||
|
final assets = [
|
||||||
|
Assets.images.dash.bumper.main.active.keyName,
|
||||||
|
Assets.images.dash.bumper.main.inactive.keyName,
|
||||||
|
Assets.images.dash.bumper.a.active.keyName,
|
||||||
|
Assets.images.dash.bumper.a.inactive.keyName,
|
||||||
|
Assets.images.dash.bumper.b.active.keyName,
|
||||||
|
Assets.images.dash.bumper.b.inactive.keyName,
|
||||||
|
];
|
||||||
|
final flameTester = FlameTester(() => TestGame(assets));
|
||||||
|
|
||||||
|
flameTester.test('"main" loads correctly', (game) async {
|
||||||
|
final bumper = DashNestBumper.main();
|
||||||
|
await game.ensureAdd(bumper);
|
||||||
|
expect(game.contains(bumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('"a" loads correctly', (game) async {
|
||||||
|
final bumper = DashNestBumper.a();
|
||||||
|
await game.ensureAdd(bumper);
|
||||||
|
|
||||||
|
expect(game.contains(bumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('"b" loads correctly', (game) async {
|
||||||
|
final bumper = DashNestBumper.b();
|
||||||
|
await game.ensureAdd(bumper);
|
||||||
|
expect(game.contains(bumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(alestiago): Consider refactoring once the following is merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
flameTester.test('closes bloc when removed', (game) async {
|
||||||
|
final bloc = MockDashNestBumperCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<DashNestBumperState>.empty(),
|
||||||
|
initialState: DashNestBumperState.inactive,
|
||||||
|
);
|
||||||
|
when(bloc.close).thenAnswer((_) async {});
|
||||||
|
final dashNestBumper = DashNestBumper.test(bloc: bloc);
|
||||||
|
|
||||||
|
await game.ensureAdd(dashNestBumper);
|
||||||
|
game.remove(dashNestBumper);
|
||||||
|
await game.ready();
|
||||||
|
|
||||||
|
verify(bloc.close).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('adds', () {
|
||||||
|
flameTester.test('adds new children', (game) async {
|
||||||
|
final component = Component();
|
||||||
|
final dashNestBumper = DashNestBumper.a(
|
||||||
|
children: [component],
|
||||||
|
);
|
||||||
|
await game.ensureAdd(dashNestBumper);
|
||||||
|
expect(dashNestBumper.children, contains(component));
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('a DashNestBumperBallContactBehavior', (game) async {
|
||||||
|
final dashNestBumper = DashNestBumper.a();
|
||||||
|
await game.ensureAdd(dashNestBumper);
|
||||||
|
expect(
|
||||||
|
dashNestBumper.children
|
||||||
|
.whereType<DashNestBumperBallContactBehavior>()
|
||||||
|
.single,
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -1,77 +0,0 @@
|
|||||||
// ignore_for_file: cascade_invocations
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_test/flame_test.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
|
|
||||||
group('DashNestBumper', () {
|
|
||||||
final assets = [
|
|
||||||
Assets.images.dash.bumper.main.active.keyName,
|
|
||||||
Assets.images.dash.bumper.main.inactive.keyName,
|
|
||||||
Assets.images.dash.bumper.a.active.keyName,
|
|
||||||
Assets.images.dash.bumper.a.inactive.keyName,
|
|
||||||
Assets.images.dash.bumper.b.active.keyName,
|
|
||||||
Assets.images.dash.bumper.b.inactive.keyName,
|
|
||||||
];
|
|
||||||
final flameTester = FlameTester(() => TestGame(assets));
|
|
||||||
|
|
||||||
flameTester.test('"main" loads correctly', (game) async {
|
|
||||||
final bumper = DashNestBumper.main();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('"a" loads correctly', (game) async {
|
|
||||||
final bumper = DashNestBumper.a();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('"b" loads correctly', (game) async {
|
|
||||||
final bumper = DashNestBumper.b();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('activate switches to active sprite', (game) async {
|
|
||||||
final bumper = DashNestBumper.main();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
final spriteGroupComponent = bumper.firstChild<SpriteGroupComponent>()!;
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(DashNestBumperSpriteState.inactive),
|
|
||||||
);
|
|
||||||
|
|
||||||
bumper.activate();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(DashNestBumperSpriteState.active),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('deactivate switches to inactive sprite', (game) async {
|
|
||||||
final bumper = DashNestBumper.main();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
final spriteGroupComponent = bumper.firstChild<SpriteGroupComponent>()!
|
|
||||||
..current = DashNestBumperSpriteState.active;
|
|
||||||
|
|
||||||
bumper.deactivate();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(DashNestBumperSpriteState.inactive),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -0,0 +1,48 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/google_letter/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
group(
|
||||||
|
'GoogleLetterBallContactBehavior',
|
||||||
|
() {
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
GoogleLetterBallContactBehavior(),
|
||||||
|
isA<GoogleLetterBallContactBehavior>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'beginContact emits onBallContacted when contacts with a ball',
|
||||||
|
(game) async {
|
||||||
|
final behavior = GoogleLetterBallContactBehavior();
|
||||||
|
final bloc = MockGoogleLetterCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<GoogleLetterState>.empty(),
|
||||||
|
initialState: GoogleLetterState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
final googleLetter = GoogleLetter.test(bloc: bloc);
|
||||||
|
await googleLetter.add(behavior);
|
||||||
|
await game.ensureAdd(googleLetter);
|
||||||
|
|
||||||
|
behavior.beginContact(MockBall(), MockContact());
|
||||||
|
|
||||||
|
verify(googleLetter.bloc.onBallContacted).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group(
|
||||||
|
'GoogleLetterCubit',
|
||||||
|
() {
|
||||||
|
blocTest<GoogleLetterCubit, GoogleLetterState>(
|
||||||
|
'onBallContacted emits active',
|
||||||
|
build: GoogleLetterCubit.new,
|
||||||
|
act: (bloc) => bloc.onBallContacted(),
|
||||||
|
expect: () => [GoogleLetterState.active],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<GoogleLetterCubit, GoogleLetterState>(
|
||||||
|
'onReset emits inactive',
|
||||||
|
build: GoogleLetterCubit.new,
|
||||||
|
act: (bloc) => bloc.onReset(),
|
||||||
|
expect: () => [GoogleLetterState.inactive],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/sparky_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
group(
|
||||||
|
'SparkyBumperBallContactBehavior',
|
||||||
|
() {
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
SparkyBumperBallContactBehavior(),
|
||||||
|
isA<SparkyBumperBallContactBehavior>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'beginContact emits onBallContacted when contacts with a ball',
|
||||||
|
(game) async {
|
||||||
|
final behavior = SparkyBumperBallContactBehavior();
|
||||||
|
final bloc = MockSparkyBumperCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<SparkyBumperState>.empty(),
|
||||||
|
initialState: SparkyBumperState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
final sparkyBumper = SparkyBumper.test(bloc: bloc);
|
||||||
|
await sparkyBumper.add(behavior);
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
|
||||||
|
behavior.beginContact(MockBall(), MockContact());
|
||||||
|
|
||||||
|
verify(sparkyBumper.bloc.onBallContacted).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/sparky_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
group(
|
||||||
|
'SparkyBumperBlinkingBehavior',
|
||||||
|
() {
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'calls onBlinked after 0.05 seconds when inactive',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
final behavior = SparkyBumperBlinkingBehavior();
|
||||||
|
final bloc = MockSparkyBumperCubit();
|
||||||
|
final streamController = StreamController<SparkyBumperState>();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
streamController.stream,
|
||||||
|
initialState: SparkyBumperState.active,
|
||||||
|
);
|
||||||
|
|
||||||
|
final sparkyBumper = SparkyBumper.test(bloc: bloc);
|
||||||
|
await sparkyBumper.add(behavior);
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
|
||||||
|
streamController.add(SparkyBumperState.inactive);
|
||||||
|
await tester.pump();
|
||||||
|
game.update(0.05);
|
||||||
|
|
||||||
|
await streamController.close();
|
||||||
|
verify(bloc.onBlinked).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group(
|
||||||
|
'SparkyBumperCubit',
|
||||||
|
() {
|
||||||
|
blocTest<SparkyBumperCubit, SparkyBumperState>(
|
||||||
|
'onBallContacted emits inactive',
|
||||||
|
build: SparkyBumperCubit.new,
|
||||||
|
act: (bloc) => bloc.onBallContacted(),
|
||||||
|
expect: () => [SparkyBumperState.inactive],
|
||||||
|
);
|
||||||
|
|
||||||
|
blocTest<SparkyBumperCubit, SparkyBumperState>(
|
||||||
|
'onBlinked emits active',
|
||||||
|
build: SparkyBumperCubit.new,
|
||||||
|
act: (bloc) => bloc.onBlinked(),
|
||||||
|
expect: () => [SparkyBumperState.active],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_components/src/components/sparky_bumper/behaviors/behaviors.dart';
|
||||||
|
|
||||||
|
import '../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final assets = [
|
||||||
|
Assets.images.sparky.bumper.a.active.keyName,
|
||||||
|
Assets.images.sparky.bumper.a.inactive.keyName,
|
||||||
|
Assets.images.sparky.bumper.b.active.keyName,
|
||||||
|
Assets.images.sparky.bumper.b.inactive.keyName,
|
||||||
|
Assets.images.sparky.bumper.c.active.keyName,
|
||||||
|
Assets.images.sparky.bumper.c.inactive.keyName,
|
||||||
|
];
|
||||||
|
final flameTester = FlameTester(() => TestGame(assets));
|
||||||
|
|
||||||
|
group('SparkyBumper', () {
|
||||||
|
flameTester.test('"a" loads correctly', (game) async {
|
||||||
|
final sparkyBumper = SparkyBumper.a();
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
expect(game.contains(sparkyBumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('"b" loads correctly', (game) async {
|
||||||
|
final sparkyBumper = SparkyBumper.b();
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
expect(game.contains(sparkyBumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('"c" loads correctly', (game) async {
|
||||||
|
final sparkyBumper = SparkyBumper.c();
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
expect(game.contains(sparkyBumper), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(alestiago): Consider refactoring once the following is merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
flameTester.test('closes bloc when removed', (game) async {
|
||||||
|
final bloc = MockSparkyBumperCubit();
|
||||||
|
whenListen(
|
||||||
|
bloc,
|
||||||
|
const Stream<SparkyBumperState>.empty(),
|
||||||
|
initialState: SparkyBumperState.active,
|
||||||
|
);
|
||||||
|
when(bloc.close).thenAnswer((_) async {});
|
||||||
|
final sparkyBumper = SparkyBumper.test(bloc: bloc);
|
||||||
|
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
game.remove(sparkyBumper);
|
||||||
|
await game.ready();
|
||||||
|
|
||||||
|
verify(bloc.close).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('adds', () {
|
||||||
|
flameTester.test('new children', (game) async {
|
||||||
|
final component = Component();
|
||||||
|
final sparkyBumper = SparkyBumper.a(
|
||||||
|
children: [component],
|
||||||
|
);
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
expect(sparkyBumper.children, contains(component));
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('a SparkyBumperBallContactBehavior', (game) async {
|
||||||
|
final sparkyBumper = SparkyBumper.a();
|
||||||
|
await game.ensureAdd(sparkyBumper);
|
||||||
|
expect(
|
||||||
|
sparkyBumper.children
|
||||||
|
.whereType<SparkyBumperBallContactBehavior>()
|
||||||
|
.single,
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
// ignore_for_file: cascade_invocations
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_test/flame_test.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
final assets = [
|
|
||||||
Assets.images.sparky.bumper.a.active.keyName,
|
|
||||||
Assets.images.sparky.bumper.a.inactive.keyName,
|
|
||||||
Assets.images.sparky.bumper.b.active.keyName,
|
|
||||||
Assets.images.sparky.bumper.b.inactive.keyName,
|
|
||||||
Assets.images.sparky.bumper.c.active.keyName,
|
|
||||||
Assets.images.sparky.bumper.c.inactive.keyName,
|
|
||||||
];
|
|
||||||
final flameTester = FlameTester(() => TestGame(assets));
|
|
||||||
|
|
||||||
group('SparkyBumper', () {
|
|
||||||
flameTester.test('"a" loads correctly', (game) async {
|
|
||||||
final bumper = SparkyBumper.a();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('"b" loads correctly', (game) async {
|
|
||||||
final bumper = SparkyBumper.b();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('"c" loads correctly', (game) async {
|
|
||||||
final bumper = SparkyBumper.c();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
expect(game.contains(bumper), isTrue);
|
|
||||||
});
|
|
||||||
|
|
||||||
flameTester.test('animate switches between on and off sprites',
|
|
||||||
(game) async {
|
|
||||||
final bumper = SparkyBumper.a();
|
|
||||||
await game.ensureAdd(bumper);
|
|
||||||
|
|
||||||
final spriteGroupComponent = bumper.firstChild<SpriteGroupComponent>()!;
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(SparkyBumperSpriteState.active),
|
|
||||||
);
|
|
||||||
|
|
||||||
final future = bumper.animate();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(SparkyBumperSpriteState.inactive),
|
|
||||||
);
|
|
||||||
|
|
||||||
await future;
|
|
||||||
|
|
||||||
expect(
|
|
||||||
spriteGroupComponent.current,
|
|
||||||
equals(SparkyBumperSpriteState.active),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -0,0 +1,95 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// Appends a new [ContactCallbacks] to the parent.
|
||||||
|
///
|
||||||
|
/// This is a convenience class for adding a [ContactCallbacks] to the parent.
|
||||||
|
/// In constract with just adding a [ContactCallbacks] to the parent's body
|
||||||
|
/// userData, this class respects the previous [ContactCallbacks] in the
|
||||||
|
/// parent's body userData, if any. Hence, it avoids overriding any previous
|
||||||
|
/// [ContactCallbacks] in the parent.
|
||||||
|
///
|
||||||
|
/// It does so by grouping the [ContactCallbacks] in a [_ContactCallbacksGroup],
|
||||||
|
/// and resetting the parent's userData accordingly.
|
||||||
|
// TODO(alestiago): Make use of generics to infer the type of the contact.
|
||||||
|
// https://github.com/VGVentures/pinball/pull/234#discussion_r859182267
|
||||||
|
// TODO(alestiago): Consider if there is a need to support adjusting a fixture's
|
||||||
|
// userData.
|
||||||
|
class ContactBehavior<T extends BodyComponent> extends Component
|
||||||
|
with ContactCallbacks, ParentIsA<T> {
|
||||||
|
@override
|
||||||
|
@mustCallSuper
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
final userData = parent.body.userData;
|
||||||
|
if (userData is _ContactCallbacksGroup) {
|
||||||
|
userData.addContactCallbacks(this);
|
||||||
|
} else if (userData is ContactCallbacks) {
|
||||||
|
final contactCallbacksGroup = _ContactCallbacksGroup()
|
||||||
|
..addContactCallbacks(userData)
|
||||||
|
..addContactCallbacks(this);
|
||||||
|
parent.body.userData = contactCallbacksGroup;
|
||||||
|
} else {
|
||||||
|
parent.body.userData = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ContactCallbacksGroup implements ContactCallbacks {
|
||||||
|
final List<ContactCallbacks> _contactCallbacks = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
@mustCallSuper
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
onBeginContact?.call(other, contact);
|
||||||
|
for (final callback in _contactCallbacks) {
|
||||||
|
callback.beginContact(other, contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@mustCallSuper
|
||||||
|
void endContact(Object other, Contact contact) {
|
||||||
|
onEndContact?.call(other, contact);
|
||||||
|
for (final callback in _contactCallbacks) {
|
||||||
|
callback.endContact(other, contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@mustCallSuper
|
||||||
|
void preSolve(Object other, Contact contact, Manifold oldManifold) {
|
||||||
|
onPreSolve?.call(other, contact, oldManifold);
|
||||||
|
for (final callback in _contactCallbacks) {
|
||||||
|
callback.preSolve(other, contact, oldManifold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@mustCallSuper
|
||||||
|
void postSolve(Object other, Contact contact, ContactImpulse impulse) {
|
||||||
|
onPostSolve?.call(other, contact, impulse);
|
||||||
|
for (final callback in _contactCallbacks) {
|
||||||
|
callback.postSolve(other, contact, impulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addContactCallbacks(ContactCallbacks callback) {
|
||||||
|
_contactCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void Function(Object other, Contact contact)? onBeginContact;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void Function(Object other, Contact contact)? onEndContact;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void Function(Object other, Contact contact, ContactImpulse impulse)?
|
||||||
|
onPostSolve;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void Function(Object other, Contact contact, Manifold oldManifold)?
|
||||||
|
onPreSolve;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
|
||||||
|
// TODO(alestiago): Remove once the following is merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1566
|
||||||
|
|
||||||
|
/// A mixin that ensures a parent is of the given type [T].
|
||||||
|
mixin ParentIsA<T extends Component> on Component {
|
||||||
|
@override
|
||||||
|
T get parent => super.parent! as T;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void>? addToParent(covariant T parent) {
|
||||||
|
return super.addToParent(parent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
class _TestBodyComponent extends BodyComponent {
|
||||||
|
@override
|
||||||
|
Body createBody() => world.createBody(BodyDef());
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestContactBehavior extends ContactBehavior {
|
||||||
|
int beginContactCallsCount = 0;
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
beginContactCallsCount++;
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
int endContactCallsCount = 0;
|
||||||
|
@override
|
||||||
|
void endContact(Object other, Contact contact) {
|
||||||
|
endContactCallsCount++;
|
||||||
|
super.endContact(other, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
int preSolveContactCallsCount = 0;
|
||||||
|
@override
|
||||||
|
void preSolve(Object other, Contact contact, Manifold oldManifold) {
|
||||||
|
preSolveContactCallsCount++;
|
||||||
|
super.preSolve(other, contact, oldManifold);
|
||||||
|
}
|
||||||
|
|
||||||
|
int postSolveContactCallsCount = 0;
|
||||||
|
@override
|
||||||
|
void postSolve(Object other, Contact contact, ContactImpulse impulse) {
|
||||||
|
postSolveContactCallsCount++;
|
||||||
|
super.postSolve(other, contact, impulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MockContactCallbacks extends Mock implements ContactCallbacks {}
|
||||||
|
|
||||||
|
class _MockContact extends Mock implements Contact {}
|
||||||
|
|
||||||
|
class _MockManifold extends Mock implements Manifold {}
|
||||||
|
|
||||||
|
class _MockContactImpulse extends Mock implements ContactImpulse {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(Forge2DGame.new);
|
||||||
|
|
||||||
|
group('ContactBehavior', () {
|
||||||
|
late Object other;
|
||||||
|
late Contact contact;
|
||||||
|
late Manifold manifold;
|
||||||
|
late ContactImpulse contactImpulse;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
other = Object();
|
||||||
|
contact = _MockContact();
|
||||||
|
manifold = _MockManifold();
|
||||||
|
contactImpulse = _MockContactImpulse();
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'should add a new ContactCallbacks to the parent',
|
||||||
|
(game) async {
|
||||||
|
final parent = _TestBodyComponent();
|
||||||
|
final contactBehavior = ContactBehavior();
|
||||||
|
await parent.add(contactBehavior);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
|
||||||
|
expect(parent.body.userData, contactBehavior);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
"should respect the previous ContactCallbacks in the parent's userData",
|
||||||
|
(game) async {
|
||||||
|
final parent = _TestBodyComponent();
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
final contactCallbacks1 = _MockContactCallbacks();
|
||||||
|
parent.body.userData = contactCallbacks1;
|
||||||
|
|
||||||
|
final contactBehavior = ContactBehavior();
|
||||||
|
await parent.ensureAdd(contactBehavior);
|
||||||
|
|
||||||
|
final contactCallbacks = parent.body.userData! as ContactCallbacks;
|
||||||
|
|
||||||
|
contactCallbacks.beginContact(other, contact);
|
||||||
|
verify(
|
||||||
|
() => contactCallbacks1.beginContact(other, contact),
|
||||||
|
).called(1);
|
||||||
|
|
||||||
|
contactCallbacks.endContact(other, contact);
|
||||||
|
verify(
|
||||||
|
() => contactCallbacks1.endContact(other, contact),
|
||||||
|
).called(1);
|
||||||
|
|
||||||
|
contactCallbacks.preSolve(other, contact, manifold);
|
||||||
|
verify(
|
||||||
|
() => contactCallbacks1.preSolve(other, contact, manifold),
|
||||||
|
).called(1);
|
||||||
|
|
||||||
|
contactCallbacks.postSolve(other, contact, contactImpulse);
|
||||||
|
verify(
|
||||||
|
() => contactCallbacks1.postSolve(other, contact, contactImpulse),
|
||||||
|
).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test('can group multiple ContactBehaviors and keep listening',
|
||||||
|
(game) async {
|
||||||
|
final parent = _TestBodyComponent();
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
|
||||||
|
final contactBehavior1 = _TestContactBehavior();
|
||||||
|
final contactBehavior2 = _TestContactBehavior();
|
||||||
|
final contactBehavior3 = _TestContactBehavior();
|
||||||
|
await parent.ensureAddAll([
|
||||||
|
contactBehavior1,
|
||||||
|
contactBehavior2,
|
||||||
|
contactBehavior3,
|
||||||
|
]);
|
||||||
|
|
||||||
|
final contactCallbacks = parent.body.userData! as ContactCallbacks;
|
||||||
|
|
||||||
|
contactCallbacks.beginContact(other, contact);
|
||||||
|
expect(contactBehavior1.beginContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior2.beginContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior3.beginContactCallsCount, equals(1));
|
||||||
|
|
||||||
|
contactCallbacks.endContact(other, contact);
|
||||||
|
expect(contactBehavior1.endContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior2.endContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior3.endContactCallsCount, equals(1));
|
||||||
|
|
||||||
|
contactCallbacks.preSolve(other, contact, manifold);
|
||||||
|
expect(contactBehavior1.preSolveContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior2.preSolveContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior3.preSolveContactCallsCount, equals(1));
|
||||||
|
|
||||||
|
contactCallbacks.postSolve(other, contact, contactImpulse);
|
||||||
|
expect(contactBehavior1.postSolveContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior2.postSolveContactCallsCount, equals(1));
|
||||||
|
expect(contactBehavior3.postSolveContactCallsCount, equals(1));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball/game/components/flutter_forest/behaviors/behaviors.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('FlutterForestBonusBehavior', () {
|
||||||
|
late GameBloc gameBloc;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
gameBloc = MockGameBloc();
|
||||||
|
whenListen(
|
||||||
|
gameBloc,
|
||||||
|
const Stream<GameState>.empty(),
|
||||||
|
initialState: const GameState.initial(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
final flameBlocTester = FlameBlocTester<PinballGame, GameBloc>(
|
||||||
|
gameBuilder: EmptyPinballTestGame.new,
|
||||||
|
blocBuilder: () => gameBloc,
|
||||||
|
);
|
||||||
|
|
||||||
|
flameBlocTester.testGameWidget(
|
||||||
|
'adds GameBonus.dashNest to the game when all bumpers are active',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
final behavior = FlutterForestBonusBehavior();
|
||||||
|
final parent = FlutterForest.test();
|
||||||
|
final bumpers = [
|
||||||
|
DashNestBumper.test(bloc: DashNestBumperCubit()),
|
||||||
|
DashNestBumper.test(bloc: DashNestBumperCubit()),
|
||||||
|
DashNestBumper.test(bloc: DashNestBumperCubit()),
|
||||||
|
];
|
||||||
|
await parent.addAll(bumpers);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
await parent.ensureAdd(behavior);
|
||||||
|
|
||||||
|
for (final bumper in bumpers) {
|
||||||
|
bumper.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => gameBloc.add(const BonusActivated(GameBonus.dashNest)),
|
||||||
|
).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameBlocTester.testGameWidget(
|
||||||
|
'adds a new ball to the game when all bumpers are active',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
final behavior = FlutterForestBonusBehavior();
|
||||||
|
final parent = FlutterForest.test();
|
||||||
|
final bumpers = [
|
||||||
|
DashNestBumper.test(bloc: DashNestBumperCubit()),
|
||||||
|
DashNestBumper.test(bloc: DashNestBumperCubit()),
|
||||||
|
DashNestBumper.test(bloc: DashNestBumperCubit()),
|
||||||
|
];
|
||||||
|
await parent.addAll(bumpers);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
await parent.ensureAdd(behavior);
|
||||||
|
|
||||||
|
for (final bumper in bumpers) {
|
||||||
|
bumper.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
await game.ready();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
game.descendants().whereType<Ball>().single,
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final assets = [
|
||||||
|
Assets.images.dash.bumper.main.active.keyName,
|
||||||
|
Assets.images.dash.bumper.main.inactive.keyName,
|
||||||
|
Assets.images.dash.bumper.a.active.keyName,
|
||||||
|
Assets.images.dash.bumper.a.inactive.keyName,
|
||||||
|
Assets.images.dash.bumper.b.active.keyName,
|
||||||
|
Assets.images.dash.bumper.b.inactive.keyName,
|
||||||
|
Assets.images.dash.animatronic.keyName,
|
||||||
|
Assets.images.signpost.inactive.keyName,
|
||||||
|
Assets.images.signpost.active1.keyName,
|
||||||
|
Assets.images.signpost.active2.keyName,
|
||||||
|
Assets.images.signpost.active3.keyName,
|
||||||
|
];
|
||||||
|
final flameTester = FlameTester(
|
||||||
|
() => EmptyPinballTestGame(assets: assets),
|
||||||
|
);
|
||||||
|
|
||||||
|
group('FlutterForest', () {
|
||||||
|
flameTester.test(
|
||||||
|
'loads correctly',
|
||||||
|
(game) async {
|
||||||
|
final flutterForest = FlutterForest();
|
||||||
|
await game.ensureAdd(flutterForest);
|
||||||
|
expect(game.contains(flutterForest), isTrue);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
group('loads', () {
|
||||||
|
flameTester.test(
|
||||||
|
'a Signpost',
|
||||||
|
(game) async {
|
||||||
|
final flutterForest = FlutterForest();
|
||||||
|
await game.ensureAdd(flutterForest);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
flutterForest.descendants().whereType<Signpost>().length,
|
||||||
|
equals(1),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'a DashAnimatronic',
|
||||||
|
(game) async {
|
||||||
|
final flutterForest = FlutterForest();
|
||||||
|
await game.ensureAdd(flutterForest);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
flutterForest.firstChild<DashAnimatronic>(),
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'three DashNestBumper',
|
||||||
|
(game) async {
|
||||||
|
final flutterForest = FlutterForest();
|
||||||
|
await game.ensureAdd(flutterForest);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
flutterForest.descendants().whereType<DashNestBumper>().length,
|
||||||
|
equals(3),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -1,177 +0,0 @@
|
|||||||
// ignore_for_file: cascade_invocations
|
|
||||||
|
|
||||||
import 'package:bloc_test/bloc_test.dart';
|
|
||||||
import 'package:flame_test/flame_test.dart';
|
|
||||||
import 'package:flutter/rendering.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() {
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
final assets = [
|
|
||||||
Assets.images.dash.bumper.main.active.keyName,
|
|
||||||
Assets.images.dash.bumper.main.inactive.keyName,
|
|
||||||
Assets.images.dash.bumper.a.active.keyName,
|
|
||||||
Assets.images.dash.bumper.a.inactive.keyName,
|
|
||||||
Assets.images.dash.bumper.b.active.keyName,
|
|
||||||
Assets.images.dash.bumper.b.inactive.keyName,
|
|
||||||
Assets.images.dash.animatronic.keyName,
|
|
||||||
Assets.images.signpost.inactive.keyName,
|
|
||||||
Assets.images.signpost.active1.keyName,
|
|
||||||
Assets.images.signpost.active2.keyName,
|
|
||||||
Assets.images.signpost.active3.keyName,
|
|
||||||
];
|
|
||||||
final flameTester = FlameTester(() => EmptyPinballTestGame(assets));
|
|
||||||
|
|
||||||
group('FlutterForest', () {
|
|
||||||
flameTester.test(
|
|
||||||
'loads correctly',
|
|
||||||
(game) async {
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAdd(flutterForest);
|
|
||||||
|
|
||||||
expect(game.contains(flutterForest), isTrue);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
group('loads', () {
|
|
||||||
flameTester.test(
|
|
||||||
'a Signpost',
|
|
||||||
(game) async {
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAdd(flutterForest);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
flutterForest.descendants().whereType<Signpost>().length,
|
|
||||||
equals(1),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameTester.test(
|
|
||||||
'a DashAnimatronic',
|
|
||||||
(game) async {
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAdd(flutterForest);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
flutterForest.firstChild<DashAnimatronic>(),
|
|
||||||
isNotNull,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameTester.test(
|
|
||||||
'three DashNestBumper',
|
|
||||||
(game) async {
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAdd(flutterForest);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
flutterForest.descendants().whereType<DashNestBumper>().length,
|
|
||||||
equals(3),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
group('bumpers', () {
|
|
||||||
late Ball ball;
|
|
||||||
late GameBloc gameBloc;
|
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
ball = Ball(baseColor: const Color(0xFF00FFFF));
|
|
||||||
});
|
|
||||||
|
|
||||||
final flameBlocTester = FlameBlocTester<PinballGame, GameBloc>(
|
|
||||||
gameBuilder: () => EmptyPinballTestGame(assets),
|
|
||||||
blocBuilder: () {
|
|
||||||
gameBloc = MockGameBloc();
|
|
||||||
const state = GameState.initial();
|
|
||||||
whenListen(gameBloc, Stream.value(state), initialState: state);
|
|
||||||
return gameBloc;
|
|
||||||
},
|
|
||||||
assets: assets,
|
|
||||||
);
|
|
||||||
|
|
||||||
flameBlocTester.testGameWidget(
|
|
||||||
'add Scored event',
|
|
||||||
setUp: (game, tester) async {
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAddAll([
|
|
||||||
flutterForest,
|
|
||||||
ball,
|
|
||||||
]);
|
|
||||||
game.addContactCallback(BallScorePointsCallback(game));
|
|
||||||
|
|
||||||
final bumpers = flutterForest.descendants().whereType<ScorePoints>();
|
|
||||||
|
|
||||||
for (final bumper in bumpers) {
|
|
||||||
beginContact(game, bumper, ball);
|
|
||||||
verify(
|
|
||||||
() => gameBloc.add(
|
|
||||||
Scored(points: bumper.points),
|
|
||||||
),
|
|
||||||
).called(1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameBlocTester.testGameWidget(
|
|
||||||
'adds GameBonus.dashNest to the game when 3 bumpers are activated',
|
|
||||||
setUp: (game, _) async {
|
|
||||||
final ball = Ball(baseColor: const Color(0xFFFF0000));
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAddAll([flutterForest, ball]);
|
|
||||||
|
|
||||||
final bumpers = flutterForest.children.whereType<DashNestBumper>();
|
|
||||||
expect(bumpers.length, equals(3));
|
|
||||||
for (final bumper in bumpers) {
|
|
||||||
beginContact(game, bumper, ball);
|
|
||||||
await game.ready();
|
|
||||||
|
|
||||||
if (bumper == bumpers.last) {
|
|
||||||
verify(
|
|
||||||
() => gameBloc.add(const BonusActivated(GameBonus.dashNest)),
|
|
||||||
).called(1);
|
|
||||||
} else {
|
|
||||||
verifyNever(
|
|
||||||
() => gameBloc.add(const BonusActivated(GameBonus.dashNest)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameBlocTester.testGameWidget(
|
|
||||||
'deactivates bumpers when 3 are active',
|
|
||||||
setUp: (game, _) async {
|
|
||||||
final ball = Ball(baseColor: const Color(0xFFFF0000));
|
|
||||||
final flutterForest = FlutterForest();
|
|
||||||
await game.ensureAddAll([flutterForest, ball]);
|
|
||||||
|
|
||||||
final bumpers = [
|
|
||||||
MockDashNestBumper(),
|
|
||||||
MockDashNestBumper(),
|
|
||||||
MockDashNestBumper(),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (final bumper in bumpers) {
|
|
||||||
flutterForest.controller.activateBumper(bumper);
|
|
||||||
await game.ready();
|
|
||||||
|
|
||||||
if (bumper == bumpers.last) {
|
|
||||||
for (final bumper in bumpers) {
|
|
||||||
verify(bumper.deactivate).called(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -0,0 +1,61 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mockingjay/mockingjay.dart';
|
||||||
|
import 'package:pinball/game/components/google_word/behaviors/behaviors.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group('GoogleWordBonusBehaviors', () {
|
||||||
|
late GameBloc gameBloc;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
gameBloc = MockGameBloc();
|
||||||
|
whenListen(
|
||||||
|
gameBloc,
|
||||||
|
const Stream<GameState>.empty(),
|
||||||
|
initialState: const GameState.initial(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
final flameBlocTester = FlameBlocTester<PinballGame, GameBloc>(
|
||||||
|
gameBuilder: EmptyPinballTestGame.new,
|
||||||
|
blocBuilder: () => gameBloc,
|
||||||
|
);
|
||||||
|
|
||||||
|
flameBlocTester.testGameWidget(
|
||||||
|
'adds GameBonus.googleWord to the game when all letters are activated',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
final behavior = GoogleWordBonusBehavior();
|
||||||
|
final parent = GoogleWord.test();
|
||||||
|
final letters = [
|
||||||
|
GoogleLetter(0),
|
||||||
|
GoogleLetter(1),
|
||||||
|
GoogleLetter(2),
|
||||||
|
GoogleLetter(3),
|
||||||
|
GoogleLetter(4),
|
||||||
|
GoogleLetter(5),
|
||||||
|
];
|
||||||
|
await parent.addAll(letters);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
await parent.ensureAdd(behavior);
|
||||||
|
|
||||||
|
for (final letter in letters) {
|
||||||
|
letter.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => gameBloc.add(const BonusActivated(GameBonus.googleWord)),
|
||||||
|
).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(EmptyPinballTestGame.new);
|
||||||
|
|
||||||
|
group('GoogleWord', () {
|
||||||
|
flameTester.test(
|
||||||
|
'loads the letters correctly',
|
||||||
|
(game) async {
|
||||||
|
const word = 'Google';
|
||||||
|
final googleWord = GoogleWord(position: Vector2.zero());
|
||||||
|
await game.ensureAdd(googleWord);
|
||||||
|
|
||||||
|
final letters = googleWord.children.whereType<GoogleLetter>();
|
||||||
|
expect(letters.length, equals(word.length));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -1,73 +0,0 @@
|
|||||||
// ignore_for_file: cascade_invocations
|
|
||||||
|
|
||||||
import 'package:bloc_test/bloc_test.dart';
|
|
||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:flame_test/flame_test.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:mockingjay/mockingjay.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
|
||||||
|
|
||||||
group('GoogleWord', () {
|
|
||||||
late GameBloc gameBloc;
|
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
gameBloc = MockGameBloc();
|
|
||||||
whenListen(
|
|
||||||
gameBloc,
|
|
||||||
const Stream<GameState>.empty(),
|
|
||||||
initialState: const GameState.initial(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
final flameTester = FlameTester(EmptyPinballTestGame.new);
|
|
||||||
final flameBlocTester = FlameBlocTester<PinballGame, GameBloc>(
|
|
||||||
gameBuilder: EmptyPinballTestGame.new,
|
|
||||||
blocBuilder: () => gameBloc,
|
|
||||||
);
|
|
||||||
|
|
||||||
flameTester.test(
|
|
||||||
'loads the letters correctly',
|
|
||||||
(game) async {
|
|
||||||
const word = 'Google';
|
|
||||||
final googleWord = GoogleWord(position: Vector2.zero());
|
|
||||||
await game.ensureAdd(googleWord);
|
|
||||||
|
|
||||||
final letters = googleWord.children.whereType<GoogleLetter>();
|
|
||||||
expect(letters.length, equals(word.length));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameBlocTester.testGameWidget(
|
|
||||||
'adds GameBonus.googleWord to the game when all letters are activated',
|
|
||||||
setUp: (game, _) async {
|
|
||||||
final ball = Ball(baseColor: const Color(0xFFFF0000));
|
|
||||||
final googleWord = GoogleWord(position: Vector2.zero());
|
|
||||||
await game.ensureAddAll([googleWord, ball]);
|
|
||||||
|
|
||||||
final letters = googleWord.children.whereType<GoogleLetter>();
|
|
||||||
expect(letters, isNotEmpty);
|
|
||||||
for (final letter in letters) {
|
|
||||||
beginContact(game, letter, ball);
|
|
||||||
await game.ready();
|
|
||||||
|
|
||||||
if (letter == letters.last) {
|
|
||||||
verify(
|
|
||||||
() => gameBloc.add(const BonusActivated(GameBonus.googleWord)),
|
|
||||||
).called(1);
|
|
||||||
} else {
|
|
||||||
verifyNever(
|
|
||||||
() => gameBloc.add(const BonusActivated(GameBonus.googleWord)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:mocktail/mocktail.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_audio/pinball_audio.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
class FakeScorePoints extends BodyComponent with ScorePoints {
|
|
||||||
@override
|
|
||||||
Body createBody() {
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get points => 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('BallScorePointsCallback', () {
|
|
||||||
late PinballGame game;
|
|
||||||
late GameBloc bloc;
|
|
||||||
late PinballAudio audio;
|
|
||||||
late Ball ball;
|
|
||||||
late FakeScorePoints fakeScorePoints;
|
|
||||||
|
|
||||||
setUp(() {
|
|
||||||
game = MockPinballGame();
|
|
||||||
bloc = MockGameBloc();
|
|
||||||
audio = MockPinballAudio();
|
|
||||||
fakeScorePoints = FakeScorePoints();
|
|
||||||
|
|
||||||
ball = MockBall();
|
|
||||||
final ballBody = MockBody();
|
|
||||||
when(() => ball.body).thenReturn(ballBody);
|
|
||||||
when(() => ballBody.position).thenReturn(Vector2.all(4));
|
|
||||||
});
|
|
||||||
|
|
||||||
setUpAll(() {
|
|
||||||
registerFallbackValue(FakeGameEvent());
|
|
||||||
});
|
|
||||||
|
|
||||||
group('begin', () {
|
|
||||||
test(
|
|
||||||
'emits Scored event with points',
|
|
||||||
() {
|
|
||||||
when(game.read<GameBloc>).thenReturn(bloc);
|
|
||||||
when(() => game.audio).thenReturn(audio);
|
|
||||||
|
|
||||||
BallScorePointsCallback(game).begin(
|
|
||||||
ball,
|
|
||||||
fakeScorePoints,
|
|
||||||
FakeContact(),
|
|
||||||
);
|
|
||||||
|
|
||||||
verify(
|
|
||||||
() => bloc.add(
|
|
||||||
Scored(points: fakeScorePoints.points),
|
|
||||||
),
|
|
||||||
).called(1);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
test(
|
|
||||||
'plays a Score sound',
|
|
||||||
() {
|
|
||||||
when(game.read<GameBloc>).thenReturn(bloc);
|
|
||||||
when(() => game.audio).thenReturn(audio);
|
|
||||||
|
|
||||||
BallScorePointsCallback(game).begin(
|
|
||||||
ball,
|
|
||||||
fakeScorePoints,
|
|
||||||
FakeContact(),
|
|
||||||
);
|
|
||||||
|
|
||||||
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);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -0,0 +1,111 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_audio/pinball_audio.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
class _TestBodyComponent extends BodyComponent {
|
||||||
|
@override
|
||||||
|
Body createBody() => world.createBody(BodyDef());
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('ScoringBehavior', () {
|
||||||
|
group('beginContact', () {
|
||||||
|
late GameBloc bloc;
|
||||||
|
late PinballAudio audio;
|
||||||
|
late Ball ball;
|
||||||
|
late BodyComponent parent;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
audio = MockPinballAudio();
|
||||||
|
|
||||||
|
ball = MockBall();
|
||||||
|
final ballBody = MockBody();
|
||||||
|
when(() => ball.body).thenReturn(ballBody);
|
||||||
|
when(() => ballBody.position).thenReturn(Vector2.all(4));
|
||||||
|
|
||||||
|
parent = _TestBodyComponent();
|
||||||
|
});
|
||||||
|
|
||||||
|
final flameBlocTester = FlameBlocTester<EmptyPinballTestGame, GameBloc>(
|
||||||
|
gameBuilder: () => EmptyPinballTestGame(
|
||||||
|
audio: audio,
|
||||||
|
),
|
||||||
|
blocBuilder: () {
|
||||||
|
bloc = MockGameBloc();
|
||||||
|
const state = GameState(
|
||||||
|
score: 0,
|
||||||
|
balls: 0,
|
||||||
|
bonusHistory: [],
|
||||||
|
);
|
||||||
|
whenListen(bloc, Stream.value(state), initialState: state);
|
||||||
|
return bloc;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameBlocTester.testGameWidget(
|
||||||
|
'emits Scored event with points',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
const points = 20;
|
||||||
|
final scoringBehavior = ScoringBehavior(points: points);
|
||||||
|
await parent.add(scoringBehavior);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
|
||||||
|
scoringBehavior.beginContact(ball, MockContact());
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => bloc.add(
|
||||||
|
const Scored(points: points),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameBlocTester.testGameWidget(
|
||||||
|
'plays score sound',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
const points = 20;
|
||||||
|
final scoringBehavior = ScoringBehavior(points: points);
|
||||||
|
await parent.add(scoringBehavior);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
|
||||||
|
scoringBehavior.beginContact(ball, MockContact());
|
||||||
|
|
||||||
|
verify(audio.score).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameBlocTester.testGameWidget(
|
||||||
|
"adds a ScoreText component at Ball's position with points",
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
const points = 20;
|
||||||
|
final scoringBehavior = ScoringBehavior(points: points);
|
||||||
|
await parent.add(scoringBehavior);
|
||||||
|
await game.ensureAdd(parent);
|
||||||
|
|
||||||
|
scoringBehavior.beginContact(ball, MockContact());
|
||||||
|
await game.ready();
|
||||||
|
|
||||||
|
final scoreText = game.descendants().whereType<ScoreText>();
|
||||||
|
expect(scoreText.length, equals(1));
|
||||||
|
expect(
|
||||||
|
scoreText.first.text,
|
||||||
|
equals(points.toString()),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
scoreText.first.position,
|
||||||
|
equals(ball.body.position),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue