feat: add sparky bumpers (#150)

* feat: added sparky bumpers

* test: tests for sparky bumpers

* feat: sandbox for sparky bumpers

* chore: unused imports

* refactor: removed Bumper and added TODO for future refactor

* fix: fixed size and tracing

* fix: fix tracing

* fix: final ellipse sizes

* refactor: different sized bumpers

* Update packages/pinball_components/lib/src/components/sparky_bumper.dart

Co-authored-by: Allison Ryan <allisonryan0002@gmail.com>
Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>
pull/162/head
Rui Miguel Alonso 4 years ago committed by GitHub
parent d798fdf9fe
commit 254c38d2a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

@ -30,6 +30,8 @@ class $AssetsImagesGen {
$AssetsImagesLaunchRampGen get launchRamp => $AssetsImagesLaunchRampGen get launchRamp =>
const $AssetsImagesLaunchRampGen(); const $AssetsImagesLaunchRampGen();
$AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen(); $AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen();
$AssetsImagesSparkyBumperGen get sparkyBumper =>
const $AssetsImagesSparkyBumperGen();
} }
class $AssetsImagesBaseboardGen { class $AssetsImagesBaseboardGen {
@ -142,6 +144,14 @@ class $AssetsImagesSpaceshipGen {
const AssetGenImage('assets/images/spaceship/saucer.png'); const AssetGenImage('assets/images/spaceship/saucer.png');
} }
class $AssetsImagesSparkyBumperGen {
const $AssetsImagesSparkyBumperGen();
$AssetsImagesSparkyBumperAGen get a => const $AssetsImagesSparkyBumperAGen();
$AssetsImagesSparkyBumperBGen get b => const $AssetsImagesSparkyBumperBGen();
$AssetsImagesSparkyBumperCGen get c => const $AssetsImagesSparkyBumperCGen();
}
class $AssetsImagesDashBumperAGen { class $AssetsImagesDashBumperAGen {
const $AssetsImagesDashBumperAGen(); const $AssetsImagesDashBumperAGen();
@ -206,6 +216,42 @@ class $AssetsImagesSpaceshipRampGen {
'assets/images/spaceship/ramp/railing-foreground.png'); 'assets/images/spaceship/ramp/railing-foreground.png');
} }
class $AssetsImagesSparkyBumperAGen {
const $AssetsImagesSparkyBumperAGen();
/// File path: assets/images/sparky_bumper/a/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/sparky_bumper/a/active.png');
/// File path: assets/images/sparky_bumper/a/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/sparky_bumper/a/inactive.png');
}
class $AssetsImagesSparkyBumperBGen {
const $AssetsImagesSparkyBumperBGen();
/// File path: assets/images/sparky_bumper/b/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/sparky_bumper/b/active.png');
/// File path: assets/images/sparky_bumper/b/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/sparky_bumper/b/inactive.png');
}
class $AssetsImagesSparkyBumperCGen {
const $AssetsImagesSparkyBumperCGen();
/// File path: assets/images/sparky_bumper/c/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/sparky_bumper/c/active.png');
/// File path: assets/images/sparky_bumper/c/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/sparky_bumper/c/inactive.png');
}
class Assets { class Assets {
Assets._(); Assets._();

@ -19,3 +19,4 @@ export 'shapes/shapes.dart';
export 'spaceship.dart'; export 'spaceship.dart';
export 'spaceship_rail.dart'; export 'spaceship_rail.dart';
export 'spaceship_ramp.dart'; export 'spaceship_ramp.dart';
export 'sparky_bumper.dart';

@ -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;
}
}

@ -39,6 +39,9 @@ flutter:
- assets/images/spaceship/ramp/ - assets/images/spaceship/ramp/
- assets/images/chrome_dino/ - assets/images/chrome_dino/
- assets/images/kicker/ - assets/images/kicker/
- assets/images/sparky_bumper/a/
- assets/images/sparky_bumper/b/
- assets/images/sparky_bumper/c/
flutter_gen: flutter_gen:
line_length: 80 line_length: 80

@ -21,5 +21,6 @@ void main() {
addChromeDinoStories(dashbook); addChromeDinoStories(dashbook);
addDashNestBumperStories(dashbook); addDashNestBumperStories(dashbook);
addKickerStories(dashbook); addKickerStories(dashbook);
addSparkyBumperStories(dashbook);
runApp(dashbook); runApp(dashbook);
} }

@ -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,
);
}

@ -6,3 +6,4 @@ export 'effects/stories.dart';
export 'flipper/stories.dart'; export 'flipper/stories.dart';
export 'layer/stories.dart'; export 'layer/stories.dart';
export 'spaceship/stories.dart'; export 'spaceship/stories.dart';
export 'sparky_bumper/stories.dart';

@ -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)),
);
});
});
}
Loading…
Cancel
Save