Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 200 KiB |
@ -0,0 +1,102 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame/flame.dart';
|
||||||
|
import 'package:flame/sprite.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
import 'package:pinball_theme/pinball_theme.dart';
|
||||||
|
|
||||||
|
/// {@template selected_character}
|
||||||
|
/// Shows an animated version of the character currently selected.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class SelectedCharacter extends StatefulWidget {
|
||||||
|
/// {@macro selected_character}
|
||||||
|
const SelectedCharacter({
|
||||||
|
Key? key,
|
||||||
|
required this.currentCharacter,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
/// The character that is selected at the moment.
|
||||||
|
final CharacterTheme currentCharacter;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SelectedCharacter> createState() => _SelectedCharacterState();
|
||||||
|
|
||||||
|
/// Returns a list of assets to be loaded.
|
||||||
|
static List<Future> loadAssets() {
|
||||||
|
return [
|
||||||
|
Flame.images.load(const DashTheme().animation.keyName),
|
||||||
|
Flame.images.load(const AndroidTheme().animation.keyName),
|
||||||
|
Flame.images.load(const DinoTheme().animation.keyName),
|
||||||
|
Flame.images.load(const SparkyTheme().animation.keyName),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SelectedCharacterState extends State<SelectedCharacter>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
SpriteAnimationController? _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_setupCharacterAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant SelectedCharacter oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
_setupCharacterAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.currentCharacter.name,
|
||||||
|
style: Theme.of(context).textTheme.headline2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Expanded(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
return SizedBox(
|
||||||
|
width: constraints.maxWidth,
|
||||||
|
height: constraints.maxHeight,
|
||||||
|
child: SpriteAnimationWidget(
|
||||||
|
controller: _controller!,
|
||||||
|
anchor: Anchor.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setupCharacterAnimation() {
|
||||||
|
final spriteSheet = SpriteSheet.fromColumnsAndRows(
|
||||||
|
image: Flame.images.fromCache(widget.currentCharacter.animation.keyName),
|
||||||
|
columns: 12,
|
||||||
|
rows: 6,
|
||||||
|
);
|
||||||
|
final animation = spriteSheet.createAnimation(
|
||||||
|
row: 0,
|
||||||
|
stepTime: 1 / 24,
|
||||||
|
to: spriteSheet.rows * spriteSheet.columns,
|
||||||
|
);
|
||||||
|
if (_controller != null) _controller?.dispose();
|
||||||
|
_controller = SpriteAnimationController(vsync: this, animation: animation)
|
||||||
|
..forward()
|
||||||
|
..repeat();
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
export 'character_selection_page.dart';
|
export 'character_selection_page.dart';
|
||||||
|
export 'selected_character.dart';
|
||||||
|
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,92 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame/effects.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
enum Points {
|
||||||
|
fiveThousand,
|
||||||
|
twentyThousand,
|
||||||
|
twoHundredThousand,
|
||||||
|
oneMillion,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template score_component}
|
||||||
|
/// A [ScoreComponent] that spawns at a given [position] with a moving
|
||||||
|
/// animation.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class ScoreComponent extends SpriteComponent with HasGameRef, ZIndex {
|
||||||
|
/// {@macro score_component}
|
||||||
|
ScoreComponent({
|
||||||
|
required this.points,
|
||||||
|
required Vector2 position,
|
||||||
|
}) : super(
|
||||||
|
position: position,
|
||||||
|
anchor: Anchor.center,
|
||||||
|
) {
|
||||||
|
zIndex = ZIndexes.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
late final Effect _effect;
|
||||||
|
|
||||||
|
late Points points;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
final sprite = Sprite(
|
||||||
|
gameRef.images.fromCache(points.asset),
|
||||||
|
);
|
||||||
|
this.sprite = sprite;
|
||||||
|
size = sprite.originalSize / 55;
|
||||||
|
|
||||||
|
await add(
|
||||||
|
_effect = MoveEffect.by(
|
||||||
|
Vector2(0, -5),
|
||||||
|
EffectController(duration: 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void update(double dt) {
|
||||||
|
super.update(dt);
|
||||||
|
|
||||||
|
if (_effect.controller.completed) {
|
||||||
|
removeFromParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PointsX on Points {
|
||||||
|
int get value {
|
||||||
|
switch (this) {
|
||||||
|
case Points.fiveThousand:
|
||||||
|
return 5000;
|
||||||
|
case Points.twentyThousand:
|
||||||
|
return 20000;
|
||||||
|
case Points.twoHundredThousand:
|
||||||
|
return 200000;
|
||||||
|
case Points.oneMillion:
|
||||||
|
return 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on Points {
|
||||||
|
String get asset {
|
||||||
|
switch (this) {
|
||||||
|
case Points.fiveThousand:
|
||||||
|
return Assets.images.score.fiveThousand.keyName;
|
||||||
|
case Points.twentyThousand:
|
||||||
|
return Assets.images.score.twentyThousand.keyName;
|
||||||
|
case Points.twoHundredThousand:
|
||||||
|
return Assets.images.score.twoHundredThousand.keyName;
|
||||||
|
case Points.oneMillion:
|
||||||
|
return Assets.images.score.oneMillion.keyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,57 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame/effects.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:pinball_flame/pinball_flame.dart';
|
|
||||||
|
|
||||||
/// {@template score_text}
|
|
||||||
/// A [TextComponent] that spawns at a given [position] with a moving animation.
|
|
||||||
/// {@endtemplate}
|
|
||||||
class ScoreText extends TextComponent with ZIndex {
|
|
||||||
/// {@macro score_text}
|
|
||||||
ScoreText({
|
|
||||||
required String text,
|
|
||||||
required Vector2 position,
|
|
||||||
this.color = Colors.black,
|
|
||||||
}) : super(
|
|
||||||
text: text,
|
|
||||||
position: position,
|
|
||||||
anchor: Anchor.center,
|
|
||||||
) {
|
|
||||||
zIndex = ZIndexes.scoreText;
|
|
||||||
}
|
|
||||||
|
|
||||||
late final Effect _effect;
|
|
||||||
|
|
||||||
/// The [text]'s [Color].
|
|
||||||
final Color color;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
textRenderer = TextPaint(
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: PinballFonts.pixeloidMono,
|
|
||||||
color: color,
|
|
||||||
fontSize: 4,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
await add(
|
|
||||||
_effect = MoveEffect.by(
|
|
||||||
Vector2(0, -5),
|
|
||||||
EffectController(duration: 1),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void update(double dt) {
|
|
||||||
super.update(dt);
|
|
||||||
|
|
||||||
if (_effect.controller.completed) {
|
|
||||||
removeFromParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,44 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flame/input.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
|
||||||
|
class ScoreGame extends AssetsGame with TapDetector {
|
||||||
|
ScoreGame()
|
||||||
|
: super(
|
||||||
|
imagesFileNames: [
|
||||||
|
Assets.images.score.fiveThousand.keyName,
|
||||||
|
Assets.images.score.twentyThousand.keyName,
|
||||||
|
Assets.images.score.twoHundredThousand.keyName,
|
||||||
|
Assets.images.score.oneMillion.keyName,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
static const description = '''
|
||||||
|
Simple game to show how score component works,
|
||||||
|
|
||||||
|
- Tap anywhere on the screen to spawn an image on the given location.
|
||||||
|
''';
|
||||||
|
|
||||||
|
final random = Random();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
camera.followVector2(Vector2.zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTapUp(TapUpInfo info) {
|
||||||
|
final index = random.nextInt(Points.values.length);
|
||||||
|
final score = Points.values[index];
|
||||||
|
|
||||||
|
add(
|
||||||
|
ScoreComponent(
|
||||||
|
points: score,
|
||||||
|
position: info.eventPosition.game..multiply(Vector2(1, -1)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:dashbook/dashbook.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/score/score_game.dart';
|
||||||
|
|
||||||
|
void addScoreStories(Dashbook dashbook) {
|
||||||
|
dashbook.storiesOf('Score').addGame(
|
||||||
|
title: 'Basic',
|
||||||
|
description: ScoreGame.description,
|
||||||
|
gameBuilder: (_) => ScoreGame(),
|
||||||
|
);
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flame/input.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:sandbox/common/common.dart';
|
|
||||||
|
|
||||||
class ScoreTextGame extends AssetsGame with TapDetector {
|
|
||||||
static const description = '''
|
|
||||||
Simple game to show how score text works,
|
|
||||||
|
|
||||||
- Tap anywhere on the screen to spawn an text on the given location.
|
|
||||||
''';
|
|
||||||
|
|
||||||
final random = Random();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
camera.followVector2(Vector2.zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onTapUp(TapUpInfo info) {
|
|
||||||
add(
|
|
||||||
ScoreText(
|
|
||||||
text: random.nextInt(100000).toString(),
|
|
||||||
color: Colors.white,
|
|
||||||
position: info.eventPosition.game..multiply(Vector2(1, -1)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import 'package:dashbook/dashbook.dart';
|
|
||||||
import 'package:sandbox/common/common.dart';
|
|
||||||
import 'package:sandbox/stories/score_text/score_text_game.dart';
|
|
||||||
|
|
||||||
void addScoreTextStories(Dashbook dashbook) {
|
|
||||||
dashbook.storiesOf('ScoreText').addGame(
|
|
||||||
title: 'Basic',
|
|
||||||
description: ScoreTextGame.description,
|
|
||||||
gameBuilder: (_) => ScoreTextGame(),
|
|
||||||
);
|
|
||||||
}
|
|
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 27 KiB |
@ -0,0 +1,202 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame/effects.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.score.fiveThousand.keyName,
|
||||||
|
Assets.images.score.twentyThousand.keyName,
|
||||||
|
Assets.images.score.twoHundredThousand.keyName,
|
||||||
|
Assets.images.score.oneMillion.keyName,
|
||||||
|
];
|
||||||
|
final flameTester = FlameTester(() => TestGame(assets));
|
||||||
|
|
||||||
|
group('ScoreComponent', () {
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'loads correctly',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
game.camera.followVector2(Vector2.zero());
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.oneMillion,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
final texts = game.descendants().whereType<SpriteComponent>().length;
|
||||||
|
expect(texts, equals(1));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'has a movement effect',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
game.camera.followVector2(Vector2.zero());
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.oneMillion,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.update(0.5);
|
||||||
|
await tester.pump();
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
final text = game.descendants().whereType<SpriteComponent>().first;
|
||||||
|
expect(text.firstChild<MoveEffect>(), isNotNull);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'is removed once finished',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
game.camera.followVector2(Vector2.zero());
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.oneMillion,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.update(1);
|
||||||
|
game.update(0); // Ensure all component removals
|
||||||
|
await tester.pump();
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
expect(game.children.length, equals(0));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
group('renders correctly', () {
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'5000 points',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.fiveThousand,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.camera
|
||||||
|
..followVector2(Vector2.zero())
|
||||||
|
..zoom = 8;
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/score/5k.png'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'20000 points',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.twentyThousand,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.camera
|
||||||
|
..followVector2(Vector2.zero())
|
||||||
|
..zoom = 8;
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/score/20k.png'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'200000 points',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.twoHundredThousand,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.camera
|
||||||
|
..followVector2(Vector2.zero())
|
||||||
|
..zoom = 8;
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/score/200k.png'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'1000000 points',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.images.loadAll(assets);
|
||||||
|
await game.ensureAdd(
|
||||||
|
ScoreComponent(
|
||||||
|
points: Points.oneMillion,
|
||||||
|
position: Vector2.zero(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.camera
|
||||||
|
..followVector2(Vector2.zero())
|
||||||
|
..zoom = 8;
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/score/1m.png'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('PointsX', () {
|
||||||
|
test('5k value return 5000', () {
|
||||||
|
expect(Points.fiveThousand.value, 5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('20k value return 20000', () {
|
||||||
|
expect(Points.twentyThousand.value, 20000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('200k value return 200000', () {
|
||||||
|
expect(Points.twoHundredThousand.value, 200000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('1m value return 1000000', () {
|
||||||
|
expect(Points.oneMillion.value, 1000000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -1,75 +0,0 @@
|
|||||||
// ignore_for_file: cascade_invocations
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame/effects.dart';
|
|
||||||
import 'package:flame_test/flame_test.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
import '../../helpers/helpers.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('ScoreText', () {
|
|
||||||
final flameTester = FlameTester(TestGame.new);
|
|
||||||
|
|
||||||
flameTester.testGameWidget(
|
|
||||||
'renders correctly',
|
|
||||||
setUp: (game, tester) async {
|
|
||||||
game.camera.followVector2(Vector2.zero());
|
|
||||||
await game.ensureAdd(
|
|
||||||
ScoreText(
|
|
||||||
text: '123',
|
|
||||||
position: Vector2.zero(),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
verify: (game, tester) async {
|
|
||||||
final texts = game.descendants().whereType<TextComponent>().length;
|
|
||||||
expect(texts, equals(1));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameTester.testGameWidget(
|
|
||||||
'has a movement effect',
|
|
||||||
setUp: (game, tester) async {
|
|
||||||
game.camera.followVector2(Vector2.zero());
|
|
||||||
await game.ensureAdd(
|
|
||||||
ScoreText(
|
|
||||||
text: '123',
|
|
||||||
position: Vector2.zero(),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
game.update(0.5);
|
|
||||||
await tester.pump();
|
|
||||||
},
|
|
||||||
verify: (game, tester) async {
|
|
||||||
final text = game.descendants().whereType<TextComponent>().first;
|
|
||||||
expect(text.firstChild<MoveEffect>(), isNotNull);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
flameTester.testGameWidget(
|
|
||||||
'is removed once finished',
|
|
||||||
setUp: (game, tester) async {
|
|
||||||
game.camera.followVector2(Vector2.zero());
|
|
||||||
await game.ensureAdd(
|
|
||||||
ScoreText(
|
|
||||||
text: '123',
|
|
||||||
position: Vector2.zero(),
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
game.update(1);
|
|
||||||
game.update(0); // Ensure all component removals
|
|
||||||
},
|
|
||||||
verify: (game, tester) async {
|
|
||||||
expect(game.children.length, equals(0));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'helpers.dart';
|
|
||||||
|
|
||||||
Future<void> expectNavigatesToRoute<Type>(
|
|
||||||
WidgetTester tester,
|
|
||||||
Route route, {
|
|
||||||
bool hasFlameGameInside = false,
|
|
||||||
}) async {
|
|
||||||
// ignore: avoid_dynamic_calls
|
|
||||||
await tester.pumpApp(
|
|
||||||
Scaffold(
|
|
||||||
body: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).push<void>(route);
|
|
||||||
},
|
|
||||||
child: const Text('Tap me'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.tap(find.text('Tap me'));
|
|
||||||
if (hasFlameGameInside) {
|
|
||||||
// We can't use pumpAndSettle here because the page renders a Flame game
|
|
||||||
// which is an infinity animation, so it will timeout
|
|
||||||
await tester.pump(); // Runs the button action
|
|
||||||
await tester.pump(); // Runs the navigation
|
|
||||||
} else {
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(find.byType(Type), findsOneWidget);
|
|
||||||
}
|
|