After Width: | Height: | Size: 306 KiB |
After Width: | Height: | Size: 422 KiB |
After Width: | Height: | Size: 171 KiB |
After Width: | Height: | Size: 222 KiB |
After Width: | Height: | Size: 298 KiB |
@ -0,0 +1,106 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flame/flame.dart';
|
||||||
|
import 'package:flame/sprite.dart';
|
||||||
|
import 'package:flame/widgets.dart';
|
||||||
|
import 'package:flutter/material.dart' hide Image;
|
||||||
|
import 'package:pinball/gen/assets.gen.dart';
|
||||||
|
|
||||||
|
class BonusAnimation extends StatelessWidget {
|
||||||
|
const BonusAnimation._(
|
||||||
|
this.imagePath, {
|
||||||
|
VoidCallback? onCompleted,
|
||||||
|
Key? key,
|
||||||
|
}) : _onCompleted = onCompleted,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
BonusAnimation.dashNest({
|
||||||
|
Key? key,
|
||||||
|
VoidCallback? onCompleted,
|
||||||
|
}) : this._(
|
||||||
|
Assets.images.bonusAnimation.dashNest.keyName,
|
||||||
|
onCompleted: onCompleted,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
BonusAnimation.sparkyTurboCharge({
|
||||||
|
Key? key,
|
||||||
|
VoidCallback? onCompleted,
|
||||||
|
}) : this._(
|
||||||
|
Assets.images.bonusAnimation.sparkyTurboCharge.keyName,
|
||||||
|
onCompleted: onCompleted,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
BonusAnimation.dino({
|
||||||
|
Key? key,
|
||||||
|
VoidCallback? onCompleted,
|
||||||
|
}) : this._(
|
||||||
|
Assets.images.bonusAnimation.dino.keyName,
|
||||||
|
onCompleted: onCompleted,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
BonusAnimation.android({
|
||||||
|
Key? key,
|
||||||
|
VoidCallback? onCompleted,
|
||||||
|
}) : this._(
|
||||||
|
Assets.images.bonusAnimation.android.keyName,
|
||||||
|
onCompleted: onCompleted,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
BonusAnimation.google({
|
||||||
|
Key? key,
|
||||||
|
VoidCallback? onCompleted,
|
||||||
|
}) : this._(
|
||||||
|
Assets.images.bonusAnimation.google.keyName,
|
||||||
|
onCompleted: onCompleted,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
final String imagePath;
|
||||||
|
|
||||||
|
final VoidCallback? _onCompleted;
|
||||||
|
|
||||||
|
static Future<void> loadAssets() {
|
||||||
|
Flame.images.prefix = '';
|
||||||
|
return Flame.images.loadAll([
|
||||||
|
Assets.images.bonusAnimation.dashNest.keyName,
|
||||||
|
Assets.images.bonusAnimation.sparkyTurboCharge.keyName,
|
||||||
|
Assets.images.bonusAnimation.dino.keyName,
|
||||||
|
Assets.images.bonusAnimation.android.keyName,
|
||||||
|
Assets.images.bonusAnimation.google.keyName,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final spriteSheet = SpriteSheet.fromColumnsAndRows(
|
||||||
|
image: Flame.images.fromCache(imagePath),
|
||||||
|
columns: 8,
|
||||||
|
rows: 9,
|
||||||
|
);
|
||||||
|
final animation = spriteSheet.createAnimation(
|
||||||
|
row: 0,
|
||||||
|
stepTime: 1 / 24,
|
||||||
|
to: spriteSheet.rows * spriteSheet.columns,
|
||||||
|
loop: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void>.delayed(
|
||||||
|
Duration(seconds: animation.totalDuration().ceil()),
|
||||||
|
() {
|
||||||
|
_onCompleted?.call();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
child: SpriteAnimationWidget(
|
||||||
|
animation: animation,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
|
export 'bonus_animation.dart';
|
||||||
export 'game_hud.dart';
|
export 'game_hud.dart';
|
||||||
export 'play_button_overlay.dart';
|
export 'play_button_overlay.dart';
|
||||||
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 825 KiB |
Before Width: | Height: | Size: 886 KiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.2 KiB |
@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart' hide Assets;
|
||||||
|
import 'package:pinball_theme/pinball_theme.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
|
||||||
|
class BackboardGameOverGame extends BasicKeyboardGame {
|
||||||
|
BackboardGameOverGame(this.score, this.character);
|
||||||
|
|
||||||
|
static const info = '''
|
||||||
|
Simple example showing the game over mode of the backboard.
|
||||||
|
|
||||||
|
- Select a character to update the character icon.
|
||||||
|
''';
|
||||||
|
|
||||||
|
final int score;
|
||||||
|
final String character;
|
||||||
|
|
||||||
|
static final characterIconPaths = <String, String>{
|
||||||
|
'Dash': Assets.images.dash.leaderboardIcon.keyName,
|
||||||
|
'Sparky': Assets.images.sparky.leaderboardIcon.keyName,
|
||||||
|
'Android': Assets.images.android.leaderboardIcon.keyName,
|
||||||
|
'Dino': Assets.images.dino.leaderboardIcon.keyName,
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
camera
|
||||||
|
..followVector2(Vector2.zero())
|
||||||
|
..zoom = 5;
|
||||||
|
|
||||||
|
await images.loadAll(characterIconPaths.values.toList());
|
||||||
|
|
||||||
|
await add(
|
||||||
|
Backboard.gameOver(
|
||||||
|
position: Vector2(0, 20),
|
||||||
|
score: score,
|
||||||
|
characterIconPath: characterIconPaths[character]!,
|
||||||
|
onSubmit: (initials) {
|
||||||
|
add(
|
||||||
|
ScoreText(
|
||||||
|
text: 'User $initials made $score',
|
||||||
|
position: Vector2(0, 50),
|
||||||
|
color: Colors.pink,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:sandbox/common/common.dart';
|
|
||||||
|
|
||||||
class BackboardGameOverGame extends BasicKeyboardGame {
|
|
||||||
BackboardGameOverGame(this.score);
|
|
||||||
|
|
||||||
static const info = '''
|
|
||||||
Simple example showing the waiting mode of the backboard.
|
|
||||||
''';
|
|
||||||
|
|
||||||
final int score;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
camera
|
|
||||||
..followVector2(Vector2.zero())
|
|
||||||
..zoom = 5;
|
|
||||||
|
|
||||||
await add(
|
|
||||||
Backboard.gameOver(
|
|
||||||
position: Vector2(0, 20),
|
|
||||||
score: score,
|
|
||||||
onSubmit: (initials) {
|
|
||||||
add(
|
|
||||||
ScoreText(
|
|
||||||
text: 'User $initials made $score',
|
|
||||||
position: Vector2(0, 50),
|
|
||||||
color: Colors.pink,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,38 @@
|
|||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/ball/basic_ball_game.dart';
|
||||||
|
|
||||||
|
class BaseboardGame extends BasicBallGame with Traceable {
|
||||||
|
static const info = '''
|
||||||
|
Shows how the Baseboards are rendered.
|
||||||
|
|
||||||
|
- Activate the "trace" parameter to overlay the body.
|
||||||
|
- Tap anywhere on the screen to spawn a ball into the game.
|
||||||
|
''';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
|
||||||
|
await images.loadAll([
|
||||||
|
Assets.images.baseboard.left.keyName,
|
||||||
|
Assets.images.baseboard.right.keyName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
final center = screenToWorld(camera.viewport.canvasSize! / 2);
|
||||||
|
final leftBaseboard = Baseboard(side: BoardSide.left)
|
||||||
|
..initialPosition = center - Vector2(25, 0)
|
||||||
|
..priority = 1;
|
||||||
|
final rightBaseboard = Baseboard(side: BoardSide.right)
|
||||||
|
..initialPosition = center + Vector2(25, 0)
|
||||||
|
..priority = 1;
|
||||||
|
|
||||||
|
await addAll([
|
||||||
|
leftBaseboard,
|
||||||
|
rightBaseboard,
|
||||||
|
]);
|
||||||
|
|
||||||
|
await traceAllBodies();
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:sandbox/common/common.dart';
|
|
||||||
|
|
||||||
class BasicBaseboardGame extends BasicGame {
|
|
||||||
static const info = 'Shows how a Baseboard works.';
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
await super.onLoad();
|
|
||||||
|
|
||||||
final center = screenToWorld(camera.viewport.canvasSize! / 2);
|
|
||||||
|
|
||||||
final leftBaseboard = Baseboard(side: BoardSide.left)
|
|
||||||
..initialPosition = center - Vector2(25, 0);
|
|
||||||
final rightBaseboard = Baseboard(side: BoardSide.right)
|
|
||||||
..initialPosition = center + Vector2(25, 0);
|
|
||||||
|
|
||||||
await addAll([
|
|
||||||
leftBaseboard,
|
|
||||||
rightBaseboard,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,15 @@
|
|||||||
import 'package:dashbook/dashbook.dart';
|
import 'package:dashbook/dashbook.dart';
|
||||||
import 'package:flame/game.dart';
|
import 'package:flame/game.dart';
|
||||||
import 'package:sandbox/common/common.dart';
|
import 'package:sandbox/common/common.dart';
|
||||||
import 'package:sandbox/stories/baseboard/basic_baseboard_game.dart';
|
import 'package:sandbox/stories/baseboard/baseboard_game.dart';
|
||||||
|
|
||||||
void addBaseboardStories(Dashbook dashbook) {
|
void addBaseboardStories(Dashbook dashbook) {
|
||||||
dashbook.storiesOf('Baseboard').add(
|
dashbook.storiesOf('Baseboard').add(
|
||||||
'Basic',
|
'Basic',
|
||||||
(context) => GameWidget(
|
(context) => GameWidget(
|
||||||
game: BasicBaseboardGame(),
|
game: BaseboardGame()..trace = context.boolProperty('Trace', true),
|
||||||
),
|
),
|
||||||
codeLink: buildSourceLink('baseboard/basic.dart'),
|
codeLink: buildSourceLink('baseboard_game/basic.dart'),
|
||||||
info: BasicBaseboardGame.info,
|
info: BaseboardGame.info,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 247 KiB After Width: | Height: | Size: 277 KiB |
Before Width: | Height: | Size: 466 KiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 38 KiB |
@ -1,101 +1,49 @@
|
|||||||
import 'package:flame/components.dart';
|
import 'package:flame/components.dart';
|
||||||
import 'package:flame/game.dart';
|
import 'package:flame/game.dart';
|
||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
const _attachedErrorMessage = "Can't add to attached Blueprints";
|
|
||||||
|
|
||||||
// TODO(erickzanardo): Keeping this inside our code base
|
// TODO(erickzanardo): Keeping this inside our code base
|
||||||
// so we can experiment with the idea, but this is a
|
// so we can experiment with the idea, but this is a
|
||||||
// potential upstream change on Flame.
|
// potential upstream change on Flame.
|
||||||
|
|
||||||
/// A [Blueprint] is a virtual way of grouping [Component]s
|
/// {@template blueprint}
|
||||||
/// that are related, but they need to be added directly on
|
/// A [Blueprint] is a virtual way of grouping [Component]s that are related,
|
||||||
/// the [FlameGame] level.
|
/// but they need to be added directly on the [FlameGame] level.
|
||||||
|
/// {@endtemplate blueprint}
|
||||||
// TODO(alestiago): refactor with feat/make-blueprint-extend-component.
|
// TODO(alestiago): refactor with feat/make-blueprint-extend-component.
|
||||||
abstract class Blueprint<T extends FlameGame> extends Component {
|
class Blueprint extends Component {
|
||||||
final List<Component> _components = [];
|
/// {@macro blueprint}
|
||||||
final List<Blueprint> _blueprints = [];
|
Blueprint({
|
||||||
|
Iterable<Component>? components,
|
||||||
bool _isAttached = false;
|
Iterable<Blueprint>? blueprints,
|
||||||
|
}) {
|
||||||
/// Called before the the [Component]s managed
|
if (components != null) _components.addAll(components);
|
||||||
/// by this blueprint is added to the [FlameGame]
|
if (blueprints != null) {
|
||||||
void build(T gameRef);
|
|
||||||
|
|
||||||
/// Attach the [Component]s built on [build] to the [game]
|
|
||||||
/// instance
|
|
||||||
@mustCallSuper
|
|
||||||
Future<void> attach(T game) async {
|
|
||||||
build(game);
|
|
||||||
await Future.wait([
|
|
||||||
game.addAll(_components),
|
|
||||||
..._blueprints.map(game.addFromBlueprint).toList(),
|
|
||||||
]);
|
|
||||||
_isAttached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a single [Component] to this blueprint.
|
|
||||||
@override
|
|
||||||
Future<void> add(Component component) async {
|
|
||||||
assert(!_isAttached, _attachedErrorMessage);
|
|
||||||
_components.add(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a list of [Blueprint]s to this blueprint.
|
|
||||||
void addAllBlueprints(List<Blueprint> blueprints) {
|
|
||||||
assert(!_isAttached, _attachedErrorMessage);
|
|
||||||
_blueprints.addAll(blueprints);
|
_blueprints.addAll(blueprints);
|
||||||
|
for (final blueprint in blueprints) {
|
||||||
|
_components.addAll(blueprint.components);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a single [Blueprint] to this blueprint.
|
|
||||||
void addBlueprint(Blueprint blueprint) {
|
|
||||||
assert(!_isAttached, _attachedErrorMessage);
|
|
||||||
_blueprints.add(blueprint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a copy of the components built by this blueprint
|
|
||||||
List<Component> get components => List.unmodifiable(_components);
|
|
||||||
|
|
||||||
/// Returns a copy of the children blueprints
|
|
||||||
List<Blueprint> get blueprints => List.unmodifiable(_blueprints);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [Blueprint] that provides additional
|
|
||||||
/// structures specific to flame_forge2d
|
|
||||||
abstract class Forge2DBlueprint extends Blueprint<Forge2DGame> {
|
|
||||||
final List<ContactCallback> _callbacks = [];
|
|
||||||
|
|
||||||
/// Adds a single [ContactCallback] to this blueprint
|
|
||||||
void addContactCallback(ContactCallback callback) {
|
|
||||||
assert(!_isAttached, _attachedErrorMessage);
|
|
||||||
_callbacks.add(callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a collection of [ContactCallback]s to this blueprint
|
final List<Component> _components = [];
|
||||||
void addAllContactCallback(List<ContactCallback> callbacks) {
|
|
||||||
assert(!_isAttached, _attachedErrorMessage);
|
|
||||||
_callbacks.addAll(callbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
final List<Component> _blueprints = [];
|
||||||
Future<void> attach(Forge2DGame game) async {
|
|
||||||
await super.attach(game);
|
|
||||||
|
|
||||||
for (final callback in _callbacks) {
|
Future<void> _addToParent(Component parent) async {
|
||||||
game.addContactCallback(callback);
|
await parent.addAll(_components);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a copy of the callbacks built by this blueprint
|
/// Returns a copy of the components built by this blueprint.
|
||||||
List<ContactCallback> get callbacks => List.unmodifiable(_callbacks);
|
List<Component> get components => List.unmodifiable(_components);
|
||||||
|
|
||||||
|
/// Returns a copy of the blueprints built by this blueprint.
|
||||||
|
List<Component> get blueprints => List.unmodifiable(_blueprints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds helper methods regardin [Blueprint]s to [FlameGame]
|
/// Adds helper methods regarding [Blueprint]s to [FlameGame].
|
||||||
extension FlameGameBlueprint on FlameGame {
|
extension FlameGameBlueprint on Component {
|
||||||
/// Shortcut to attach a [Blueprint] instance to this game
|
/// Shortcut to add a [Blueprint]s components to its parent.
|
||||||
/// equivalent to `MyBluepinrt().attach(game)`
|
|
||||||
Future<void> addFromBlueprint(Blueprint blueprint) async {
|
Future<void> addFromBlueprint(Blueprint blueprint) async {
|
||||||
await blueprint.attach(this);
|
await blueprint._addToParent(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,138 +1,86 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
import 'package:flame/components.dart';
|
||||||
import 'package:flame_forge2d/contact_callbacks.dart';
|
import 'package:flame/game.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
|
||||||
import 'package:pinball_flame/pinball_flame.dart';
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
import '../helpers/helpers.dart';
|
|
||||||
|
|
||||||
class TestContactCallback extends ContactCallback<dynamic, dynamic> {}
|
|
||||||
|
|
||||||
class MyBlueprint extends Blueprint {
|
|
||||||
@override
|
|
||||||
void build(_) {
|
|
||||||
add(Component());
|
|
||||||
addAll([Component(), Component()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyOtherBlueprint extends Blueprint {
|
|
||||||
@override
|
|
||||||
void build(_) {
|
|
||||||
add(Component());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class YetMyOtherBlueprint extends Blueprint {
|
|
||||||
@override
|
|
||||||
void build(_) {
|
|
||||||
add(Component());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyComposedBlueprint extends Blueprint {
|
|
||||||
@override
|
|
||||||
void build(_) {
|
|
||||||
addBlueprint(MyBlueprint());
|
|
||||||
addAllBlueprints([MyOtherBlueprint(), YetMyOtherBlueprint()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyForge2dBlueprint extends Forge2DBlueprint {
|
|
||||||
@override
|
|
||||||
void build(_) {
|
|
||||||
addContactCallback(MockContactCallback());
|
|
||||||
addAllContactCallback([MockContactCallback(), MockContactCallback()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('Blueprint', () {
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
setUpAll(() {
|
|
||||||
registerFallbackValue(MyBlueprint());
|
|
||||||
registerFallbackValue(Component());
|
|
||||||
});
|
|
||||||
|
|
||||||
test('components can be added to it', () {
|
|
||||||
final blueprint = MyBlueprint()..build(MockForge2DGame());
|
|
||||||
|
|
||||||
expect(blueprint.components.length, equals(3));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('blueprints can be added to it', () {
|
|
||||||
final blueprint = MyComposedBlueprint()..build(MockForge2DGame());
|
|
||||||
|
|
||||||
expect(blueprint.blueprints.length, equals(3));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('adds the components to a game on attach', () {
|
group('Blueprint', () {
|
||||||
final mockGame = MockForge2DGame();
|
final flameTester = FlameTester(FlameGame.new);
|
||||||
when(() => mockGame.addAll(any())).thenAnswer((_) async {});
|
|
||||||
MyBlueprint().attach(mockGame);
|
test('correctly sets and gets components', () {
|
||||||
|
final component1 = Component();
|
||||||
|
final component2 = Component();
|
||||||
|
final blueprint = Blueprint(
|
||||||
|
components: [
|
||||||
|
component1,
|
||||||
|
component2,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
verify(() => mockGame.addAll(any())).called(1);
|
expect(blueprint.components.length, 2);
|
||||||
|
expect(blueprint.components, contains(component1));
|
||||||
|
expect(blueprint.components, contains(component2));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('adds components from a child Blueprint the to a game on attach', () {
|
test('correctly sets and gets blueprints', () {
|
||||||
final mockGame = MockForge2DGame();
|
final blueprint2 = Blueprint(
|
||||||
when(() => mockGame.addAll(any())).thenAnswer((_) async {});
|
components: [Component()],
|
||||||
MyComposedBlueprint().attach(mockGame);
|
);
|
||||||
|
final blueprint1 = Blueprint(
|
||||||
|
components: [Component()],
|
||||||
|
blueprints: [blueprint2],
|
||||||
|
);
|
||||||
|
|
||||||
verify(() => mockGame.addAll(any())).called(4);
|
expect(blueprint1.blueprints, contains(blueprint2));
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
flameTester.test('adds the components to parent on attach', (game) async {
|
||||||
'throws assertion error when adding to an already attached blueprint',
|
final blueprint = Blueprint(
|
||||||
() async {
|
components: [
|
||||||
final mockGame = MockForge2DGame();
|
Component(),
|
||||||
when(() => mockGame.addAll(any())).thenAnswer((_) async {});
|
Component(),
|
||||||
final blueprint = MyBlueprint();
|
],
|
||||||
await blueprint.attach(mockGame);
|
|
||||||
|
|
||||||
expect(() => blueprint.add(Component()), throwsAssertionError);
|
|
||||||
expect(() => blueprint.addAll([Component()]), throwsAssertionError);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
await game.addFromBlueprint(blueprint);
|
||||||
|
await game.ready();
|
||||||
|
|
||||||
group('Forge2DBlueprint', () {
|
for (final component in blueprint.components) {
|
||||||
setUpAll(() {
|
expect(game.children.contains(component), isTrue);
|
||||||
registerFallbackValue(TestContactCallback());
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('callbacks can be added to it', () {
|
flameTester.test('adds components from a child Blueprint', (game) async {
|
||||||
final blueprint = MyForge2dBlueprint()..build(MockForge2DGame());
|
final childBlueprint = Blueprint(
|
||||||
|
components: [
|
||||||
expect(blueprint.callbacks.length, equals(3));
|
Component(),
|
||||||
});
|
Component(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final parentBlueprint = Blueprint(
|
||||||
|
components: [
|
||||||
|
Component(),
|
||||||
|
Component(),
|
||||||
|
],
|
||||||
|
blueprints: [
|
||||||
|
childBlueprint,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
test('adds the callbacks to a game on attach', () async {
|
await game.addFromBlueprint(parentBlueprint);
|
||||||
final mockGame = MockForge2DGame();
|
await game.ready();
|
||||||
when(() => mockGame.addAll(any())).thenAnswer((_) async {});
|
|
||||||
when(() => mockGame.addContactCallback(any())).thenAnswer((_) async {});
|
|
||||||
await MyForge2dBlueprint().attach(mockGame);
|
|
||||||
|
|
||||||
verify(() => mockGame.addContactCallback(any())).called(3);
|
for (final component in childBlueprint.components) {
|
||||||
|
expect(game.children, contains(component));
|
||||||
|
expect(parentBlueprint.components, contains(component));
|
||||||
|
}
|
||||||
|
for (final component in parentBlueprint.components) {
|
||||||
|
expect(game.children, contains(component));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
|
||||||
'throws assertion error when adding to an already attached blueprint',
|
|
||||||
() async {
|
|
||||||
final mockGame = MockForge2DGame();
|
|
||||||
when(() => mockGame.addAll(any())).thenAnswer((_) async {});
|
|
||||||
when(() => mockGame.addContactCallback(any())).thenAnswer((_) async {});
|
|
||||||
final blueprint = MyForge2dBlueprint();
|
|
||||||
await blueprint.attach(mockGame);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
() => blueprint.addContactCallback(MockContactCallback()),
|
|
||||||
throwsAssertionError,
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
() => blueprint.addAllContactCallback([MockContactCallback()]),
|
|
||||||
throwsAssertionError,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
After Width: | Height: | Size: 996 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 723 B |
After Width: | Height: | Size: 789 B |
@ -0,0 +1,99 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:flame/assets.dart';
|
||||||
|
import 'package:flame/widgets.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:pinball/game/view/widgets/bonus_animation.dart';
|
||||||
|
|
||||||
|
import '../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
class MockImages extends Mock implements Images {}
|
||||||
|
|
||||||
|
class MockImage extends Mock implements ui.Image {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
await BonusAnimation.loadAssets();
|
||||||
|
});
|
||||||
|
|
||||||
|
group('loads SpriteAnimationWidget correctly for', () {
|
||||||
|
testWidgets('dashNest', (tester) async {
|
||||||
|
await tester.pumpApp(
|
||||||
|
BonusAnimation.dashNest(),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.byType(SpriteAnimationWidget), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('dino', (tester) async {
|
||||||
|
await tester.pumpApp(
|
||||||
|
BonusAnimation.dino(),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.byType(SpriteAnimationWidget), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('sparkyTurboCharge', (tester) async {
|
||||||
|
await tester.pumpApp(
|
||||||
|
BonusAnimation.sparkyTurboCharge(),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.byType(SpriteAnimationWidget), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('google', (tester) async {
|
||||||
|
await tester.pumpApp(
|
||||||
|
BonusAnimation.google(),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.byType(SpriteAnimationWidget), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('android', (tester) async {
|
||||||
|
await tester.pumpApp(
|
||||||
|
BonusAnimation.android(),
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(find.byType(SpriteAnimationWidget), findsOneWidget);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(arturplaczek): refactor this test when there is a new version of the
|
||||||
|
// flame with an onComplete callback in SpriteAnimationWidget
|
||||||
|
// https://github.com/flame-engine/flame/issues/1543
|
||||||
|
testWidgets('called onCompleted callback at the end of animation ',
|
||||||
|
(tester) async {
|
||||||
|
final completer = Completer<void>();
|
||||||
|
|
||||||
|
await tester.runAsync(() async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: BonusAnimation.dashNest(
|
||||||
|
onCompleted: completer.complete,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 4));
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(completer.isCompleted, isTrue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|