After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.1 KiB |
@ -0,0 +1,138 @@
|
|||||||
|
// ignore_for_file: avoid_renaming_method_parameters
|
||||||
|
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// {@template slingshots}
|
||||||
|
/// A [Blueprint] which creates the left and right pairs of [Slingshot]s.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class Slingshots extends Forge2DBlueprint {
|
||||||
|
@override
|
||||||
|
void build(_) {
|
||||||
|
// TODO(allisonryan0002): use radians values instead of converting degrees.
|
||||||
|
final leftUpperSlingshot = Slingshot(
|
||||||
|
length: 5.66,
|
||||||
|
angle: -1.5 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.leftUpper.keyName,
|
||||||
|
)..initialPosition = Vector2(-29, 1.5);
|
||||||
|
|
||||||
|
final leftLowerSlingshot = Slingshot(
|
||||||
|
length: 3.54,
|
||||||
|
angle: -29.1 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.leftLower.keyName,
|
||||||
|
)..initialPosition = Vector2(-31, -6.2);
|
||||||
|
|
||||||
|
final rightUpperSlingshot = Slingshot(
|
||||||
|
length: 5.64,
|
||||||
|
angle: 1 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.rightUpper.keyName,
|
||||||
|
)..initialPosition = Vector2(22.3, 1.58);
|
||||||
|
|
||||||
|
final rightLowerSlingshot = Slingshot(
|
||||||
|
length: 3.46,
|
||||||
|
angle: 26.8 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.rightLower.keyName,
|
||||||
|
)..initialPosition = Vector2(24.7, -6.2);
|
||||||
|
|
||||||
|
addAll([
|
||||||
|
leftUpperSlingshot,
|
||||||
|
leftLowerSlingshot,
|
||||||
|
rightUpperSlingshot,
|
||||||
|
rightLowerSlingshot,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template slingshot}
|
||||||
|
/// Elastic bumper that bounces the [Ball] off of its straight sides.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class Slingshot extends BodyComponent with InitialPosition {
|
||||||
|
/// {@macro slingshot}
|
||||||
|
Slingshot({
|
||||||
|
required double length,
|
||||||
|
required double angle,
|
||||||
|
required String spritePath,
|
||||||
|
}) : _length = length,
|
||||||
|
_angle = angle,
|
||||||
|
_spritePath = spritePath,
|
||||||
|
super(priority: 1);
|
||||||
|
|
||||||
|
final double _length;
|
||||||
|
|
||||||
|
final double _angle;
|
||||||
|
|
||||||
|
final String _spritePath;
|
||||||
|
|
||||||
|
List<FixtureDef> _createFixtureDefs() {
|
||||||
|
final fixturesDef = <FixtureDef>[];
|
||||||
|
const circleRadius = 1.55;
|
||||||
|
|
||||||
|
final topCircleShape = CircleShape()..radius = circleRadius;
|
||||||
|
topCircleShape.position.setValues(0, _length / 2);
|
||||||
|
final topCircleFixtureDef = FixtureDef(topCircleShape)..friction = 0;
|
||||||
|
fixturesDef.add(topCircleFixtureDef);
|
||||||
|
|
||||||
|
final bottomCircleShape = CircleShape()..radius = circleRadius;
|
||||||
|
bottomCircleShape.position.setValues(0, -_length / 2);
|
||||||
|
final bottomCircleFixtureDef = FixtureDef(bottomCircleShape)..friction = 0;
|
||||||
|
fixturesDef.add(bottomCircleFixtureDef);
|
||||||
|
|
||||||
|
final leftEdgeShape = EdgeShape()
|
||||||
|
..set(
|
||||||
|
Vector2(circleRadius, _length / 2),
|
||||||
|
Vector2(circleRadius, -_length / 2),
|
||||||
|
);
|
||||||
|
final leftEdgeShapeFixtureDef = FixtureDef(leftEdgeShape)
|
||||||
|
..friction = 0
|
||||||
|
..restitution = 5;
|
||||||
|
fixturesDef.add(leftEdgeShapeFixtureDef);
|
||||||
|
|
||||||
|
final rightEdgeShape = EdgeShape()
|
||||||
|
..set(
|
||||||
|
Vector2(-circleRadius, _length / 2),
|
||||||
|
Vector2(-circleRadius, -_length / 2),
|
||||||
|
);
|
||||||
|
final rightEdgeShapeFixtureDef = FixtureDef(rightEdgeShape)
|
||||||
|
..friction = 0
|
||||||
|
..restitution = 5;
|
||||||
|
fixturesDef.add(rightEdgeShapeFixtureDef);
|
||||||
|
|
||||||
|
return fixturesDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Body createBody() {
|
||||||
|
final bodyDef = BodyDef()
|
||||||
|
..userData = this
|
||||||
|
..position = initialPosition
|
||||||
|
..angle = _angle;
|
||||||
|
|
||||||
|
final body = world.createBody(bodyDef);
|
||||||
|
_createFixtureDefs().forEach(body.createFixture);
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
await _loadSprite();
|
||||||
|
renderBody = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadSprite() async {
|
||||||
|
final sprite = await gameRef.loadSprite(_spritePath);
|
||||||
|
|
||||||
|
await add(
|
||||||
|
SpriteComponent(
|
||||||
|
sprite: sprite,
|
||||||
|
size: sprite.originalSize / 10,
|
||||||
|
anchor: Anchor.center,
|
||||||
|
angle: _angle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// {@template sparky_bumper}
|
||||||
|
/// Bumper for Sparky area.
|
||||||
|
/// {@endtemplate}
|
||||||
|
// TODO(ruimiguel): refactor later to unify with DashBumpers.
|
||||||
|
class SparkyBumper extends BodyComponent with InitialPosition {
|
||||||
|
/// {@macro sparky_bumper}
|
||||||
|
SparkyBumper._({
|
||||||
|
required double majorRadius,
|
||||||
|
required double minorRadius,
|
||||||
|
required String activeAssetPath,
|
||||||
|
required String inactiveAssetPath,
|
||||||
|
required SpriteComponent spriteComponent,
|
||||||
|
}) : _majorRadius = majorRadius,
|
||||||
|
_minorRadius = minorRadius,
|
||||||
|
_activeAssetPath = activeAssetPath,
|
||||||
|
_inactiveAssetPath = inactiveAssetPath,
|
||||||
|
_spriteComponent = spriteComponent;
|
||||||
|
|
||||||
|
/// {@macro sparky_bumper}
|
||||||
|
SparkyBumper.a()
|
||||||
|
: this._(
|
||||||
|
majorRadius: 2.9,
|
||||||
|
minorRadius: 2.1,
|
||||||
|
activeAssetPath: Assets.images.sparkyBumper.a.active.keyName,
|
||||||
|
inactiveAssetPath: Assets.images.sparkyBumper.a.inactive.keyName,
|
||||||
|
spriteComponent: SpriteComponent(
|
||||||
|
anchor: Anchor.center,
|
||||||
|
position: Vector2(0, -0.25),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// {@macro sparky_bumper}
|
||||||
|
SparkyBumper.b()
|
||||||
|
: this._(
|
||||||
|
majorRadius: 2.85,
|
||||||
|
minorRadius: 2,
|
||||||
|
activeAssetPath: Assets.images.sparkyBumper.b.active.keyName,
|
||||||
|
inactiveAssetPath: Assets.images.sparkyBumper.b.inactive.keyName,
|
||||||
|
spriteComponent: SpriteComponent(
|
||||||
|
anchor: Anchor.center,
|
||||||
|
position: Vector2(0, -0.35),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// {@macro sparky_bumper}
|
||||||
|
SparkyBumper.c()
|
||||||
|
: this._(
|
||||||
|
majorRadius: 3,
|
||||||
|
minorRadius: 2.2,
|
||||||
|
activeAssetPath: Assets.images.sparkyBumper.c.active.keyName,
|
||||||
|
inactiveAssetPath: Assets.images.sparkyBumper.c.inactive.keyName,
|
||||||
|
spriteComponent: SpriteComponent(
|
||||||
|
anchor: Anchor.center,
|
||||||
|
position: Vector2(0, -0.4),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final double _majorRadius;
|
||||||
|
final double _minorRadius;
|
||||||
|
final String _activeAssetPath;
|
||||||
|
late final Sprite _activeSprite;
|
||||||
|
final String _inactiveAssetPath;
|
||||||
|
late final Sprite _inactiveSprite;
|
||||||
|
final SpriteComponent _spriteComponent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
await _loadSprites();
|
||||||
|
|
||||||
|
// TODO(erickzanardo): Look into using onNewState instead.
|
||||||
|
// Currently doing: onNewState(gameRef.read<GameState>()) will throw an
|
||||||
|
// `Exception: build context is not available yet`
|
||||||
|
deactivate();
|
||||||
|
await add(_spriteComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Body createBody() {
|
||||||
|
renderBody = false;
|
||||||
|
|
||||||
|
final shape = EllipseShape(
|
||||||
|
center: Vector2.zero(),
|
||||||
|
majorRadius: _majorRadius,
|
||||||
|
minorRadius: _minorRadius,
|
||||||
|
)..rotate(math.pi / 1.9);
|
||||||
|
final fixtureDef = FixtureDef(shape)
|
||||||
|
..friction = 0
|
||||||
|
..restitution = 4;
|
||||||
|
|
||||||
|
final bodyDef = BodyDef()
|
||||||
|
..position = initialPosition
|
||||||
|
..userData = this;
|
||||||
|
|
||||||
|
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadSprites() async {
|
||||||
|
// TODO(alestiago): I think ideally we would like to do:
|
||||||
|
// Sprite(path).load so we don't require to store the activeAssetPath and
|
||||||
|
// the inactive assetPath.
|
||||||
|
_inactiveSprite = await gameRef.loadSprite(_inactiveAssetPath);
|
||||||
|
_activeSprite = await gameRef.loadSprite(_activeAssetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activates the [DashNestBumper].
|
||||||
|
void activate() {
|
||||||
|
_spriteComponent
|
||||||
|
..sprite = _activeSprite
|
||||||
|
..size = _activeSprite.originalSize / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deactivates the [DashNestBumper].
|
||||||
|
void deactivate() {
|
||||||
|
_spriteComponent
|
||||||
|
..sprite = _inactiveSprite
|
||||||
|
..size = _inactiveSprite.originalSize / 10;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:flame/extensions.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/ball/basic_ball_game.dart';
|
||||||
|
|
||||||
|
class SlingshotGame extends BasicBallGame {
|
||||||
|
SlingshotGame({
|
||||||
|
required this.trace,
|
||||||
|
}) : super(color: const Color(0xFFFF0000));
|
||||||
|
|
||||||
|
static const info = '''
|
||||||
|
Shows how Slingshots are rendered.
|
||||||
|
|
||||||
|
- Activate the "trace" parameter to overlay the body.
|
||||||
|
- Tap anywhere on the screen to spawn a ball into the game.
|
||||||
|
''';
|
||||||
|
|
||||||
|
final bool trace;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
|
||||||
|
final center = screenToWorld(camera.viewport.canvasSize! / 2);
|
||||||
|
|
||||||
|
final leftUpperSlingshot = Slingshot(
|
||||||
|
length: 5.66,
|
||||||
|
angle: -1.5 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.leftUpper.keyName,
|
||||||
|
)..initialPosition = center + Vector2(-29, 1.5);
|
||||||
|
|
||||||
|
final leftLowerSlingshot = Slingshot(
|
||||||
|
length: 3.54,
|
||||||
|
angle: -29.1 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.leftLower.keyName,
|
||||||
|
)..initialPosition = center + Vector2(-31, -6.2);
|
||||||
|
|
||||||
|
final rightUpperSlingshot = Slingshot(
|
||||||
|
length: 5.64,
|
||||||
|
angle: 1 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.rightUpper.keyName,
|
||||||
|
)..initialPosition = center + Vector2(22.3, 1.58);
|
||||||
|
|
||||||
|
final rightLowerSlingshot = Slingshot(
|
||||||
|
length: 3.46,
|
||||||
|
angle: 26.8 * (math.pi / 180),
|
||||||
|
spritePath: Assets.images.slingshot.rightLower.keyName,
|
||||||
|
)..initialPosition = center + Vector2(24.7, -6.2);
|
||||||
|
|
||||||
|
await addAll([
|
||||||
|
leftUpperSlingshot,
|
||||||
|
leftLowerSlingshot,
|
||||||
|
rightUpperSlingshot,
|
||||||
|
rightLowerSlingshot,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (trace) {
|
||||||
|
leftUpperSlingshot.trace();
|
||||||
|
leftLowerSlingshot.trace();
|
||||||
|
rightUpperSlingshot.trace();
|
||||||
|
rightLowerSlingshot.trace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:dashbook/dashbook.dart';
|
||||||
|
import 'package:flame/game.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/slingshot/slingshot_game.dart';
|
||||||
|
|
||||||
|
void addSlingshotStories(Dashbook dashbook) {
|
||||||
|
dashbook.storiesOf('Slingshots').add(
|
||||||
|
'Basic',
|
||||||
|
(context) => GameWidget(
|
||||||
|
game: SlingshotGame(
|
||||||
|
trace: context.boolProperty('Trace', true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
codeLink: buildSourceLink('slingshot_game/basic.dart'),
|
||||||
|
info: SlingshotGame.info,
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flame/extensions.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/ball/basic_ball_game.dart';
|
||||||
|
|
||||||
|
class SparkyBumperGame extends BasicBallGame {
|
||||||
|
SparkyBumperGame({
|
||||||
|
required this.trace,
|
||||||
|
}) : super(color: const Color(0xFF0000FF));
|
||||||
|
|
||||||
|
static const info = '''
|
||||||
|
Shows how a SparkyBumper is rendered.
|
||||||
|
|
||||||
|
Activate the "trace" parameter to overlay the body.
|
||||||
|
''';
|
||||||
|
|
||||||
|
final bool trace;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
|
||||||
|
final center = screenToWorld(camera.viewport.canvasSize! / 2);
|
||||||
|
final sparkyBumperA = SparkyBumper.a()
|
||||||
|
..initialPosition = Vector2(center.x - 20, center.y - 20)
|
||||||
|
..priority = 1;
|
||||||
|
final sparkyBumperB = SparkyBumper.b()
|
||||||
|
..initialPosition = Vector2(center.x - 10, center.y + 10)
|
||||||
|
..priority = 1;
|
||||||
|
final sparkyBumperC = SparkyBumper.c()
|
||||||
|
..initialPosition = Vector2(center.x + 20, center.y)
|
||||||
|
..priority = 1;
|
||||||
|
await addAll([
|
||||||
|
sparkyBumperA,
|
||||||
|
sparkyBumperB,
|
||||||
|
sparkyBumperC,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (trace) {
|
||||||
|
sparkyBumperA.trace();
|
||||||
|
sparkyBumperB.trace();
|
||||||
|
sparkyBumperC.trace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:dashbook/dashbook.dart';
|
||||||
|
import 'package:flame/game.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/sparky_bumper/sparky_bumper_game.dart';
|
||||||
|
|
||||||
|
void addSparkyBumperStories(Dashbook dashbook) {
|
||||||
|
dashbook.storiesOf('Sparky Bumpers').add(
|
||||||
|
'Basic',
|
||||||
|
(context) => GameWidget(
|
||||||
|
game: SparkyBumperGame(
|
||||||
|
trace: context.boolProperty('Trace', true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
codeLink: buildSourceLink('sparky_bumper/basic.dart'),
|
||||||
|
info: SparkyBumperGame.info,
|
||||||
|
);
|
||||||
|
}
|
After Width: | Height: | Size: 49 KiB |
@ -0,0 +1,97 @@
|
|||||||
|
// 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:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('Slingshot', () {
|
||||||
|
final flameTester = FlameTester(TestGame.new);
|
||||||
|
const length = 2.0;
|
||||||
|
const angle = 0.0;
|
||||||
|
final spritePath = Assets.images.slingshot.leftUpper.keyName;
|
||||||
|
|
||||||
|
flameTester.testGameWidget(
|
||||||
|
'renders correctly',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
await game.addFromBlueprint(Slingshots());
|
||||||
|
await game.ready();
|
||||||
|
game.camera.followVector2(Vector2.zero());
|
||||||
|
},
|
||||||
|
// TODO(allisonryan0002): enable test when workflows are fixed.
|
||||||
|
// verify: (game, tester) async {
|
||||||
|
// await expectLater(
|
||||||
|
// find.byGame<Forge2DGame>(),
|
||||||
|
// matchesGoldenFile('golden/slingshots.png'),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'loads correctly',
|
||||||
|
(game) async {
|
||||||
|
final slingshot = Slingshot(
|
||||||
|
length: length,
|
||||||
|
angle: angle,
|
||||||
|
spritePath: spritePath,
|
||||||
|
);
|
||||||
|
await game.ensureAdd(slingshot);
|
||||||
|
|
||||||
|
expect(game.contains(slingshot), isTrue);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'body is static',
|
||||||
|
(game) async {
|
||||||
|
final slingshot = Slingshot(
|
||||||
|
length: length,
|
||||||
|
angle: angle,
|
||||||
|
spritePath: spritePath,
|
||||||
|
);
|
||||||
|
await game.ensureAdd(slingshot);
|
||||||
|
|
||||||
|
expect(slingshot.body.bodyType, equals(BodyType.static));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'has restitution',
|
||||||
|
(game) async {
|
||||||
|
final slingshot = Slingshot(
|
||||||
|
length: length,
|
||||||
|
angle: angle,
|
||||||
|
spritePath: spritePath,
|
||||||
|
);
|
||||||
|
await game.ensureAdd(slingshot);
|
||||||
|
|
||||||
|
final totalRestitution = slingshot.body.fixtures.fold<double>(
|
||||||
|
0,
|
||||||
|
(total, fixture) => total + fixture.restitution,
|
||||||
|
);
|
||||||
|
expect(totalRestitution, greaterThan(0));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'has no friction',
|
||||||
|
(game) async {
|
||||||
|
final slingshot = Slingshot(
|
||||||
|
length: length,
|
||||||
|
angle: angle,
|
||||||
|
spritePath: spritePath,
|
||||||
|
);
|
||||||
|
await game.ensureAdd(slingshot);
|
||||||
|
|
||||||
|
final totalFriction = slingshot.body.fixtures.fold<double>(
|
||||||
|
0,
|
||||||
|
(total, fixture) => total + fixture.friction,
|
||||||
|
);
|
||||||
|
expect(totalFriction, equals(0));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
// 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 flameTester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
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('activate returns normally', (game) async {
|
||||||
|
final bumper = SparkyBumper.a();
|
||||||
|
await game.ensureAdd(bumper);
|
||||||
|
|
||||||
|
expect(bumper.activate, returnsNormally);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('deactivate returns normally', (game) async {
|
||||||
|
final bumper = SparkyBumper.a();
|
||||||
|
await game.ensureAdd(bumper);
|
||||||
|
|
||||||
|
expect(bumper.deactivate, returnsNormally);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('changes sprite', (game) async {
|
||||||
|
final bumper = SparkyBumper.a();
|
||||||
|
await game.ensureAdd(bumper);
|
||||||
|
|
||||||
|
final spriteComponent = bumper.firstChild<SpriteComponent>()!;
|
||||||
|
|
||||||
|
final deactivatedSprite = spriteComponent.sprite;
|
||||||
|
bumper.activate();
|
||||||
|
expect(
|
||||||
|
spriteComponent.sprite,
|
||||||
|
isNot(equals(deactivatedSprite)),
|
||||||
|
);
|
||||||
|
|
||||||
|
final activatedSprite = spriteComponent.sprite;
|
||||||
|
bumper.deactivate();
|
||||||
|
expect(
|
||||||
|
spriteComponent.sprite,
|
||||||
|
isNot(equals(activatedSprite)),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
activatedSprite,
|
||||||
|
isNot(equals(deactivatedSprite)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
|
||||||
|
void beginContact(Forge2DGame game, BodyComponent bodyA, BodyComponent bodyB) {
|
||||||
|
assert(
|
||||||
|
bodyA.body.fixtures.isNotEmpty && bodyB.body.fixtures.isNotEmpty,
|
||||||
|
'Bodies require fixtures to contact each other.',
|
||||||
|
);
|
||||||
|
|
||||||
|
final fixtureA = bodyA.body.fixtures.first;
|
||||||
|
final fixtureB = bodyB.body.fixtures.first;
|
||||||
|
final contact = Contact.init(fixtureA, 0, fixtureB, 0);
|
||||||
|
game.world.contactManager.contactListener?.beginContact(contact);
|
||||||
|
}
|