refactor: SpriteComponent subclassing (#158)

* refactor: remove _loadSprites

* feat: defined BallSprite

* refactor: removed late SpriteComponent

* refactor: defined BaseboardSprite

* refactor: defined DinoWalls sprites

* refactor: defined FlutterSIgnPostSprite

* refactor: defined KickerSprite

* refactor: defined LaunchRampSprite

* refactor: removed trailing comma

* refactor: defined _AndroidHeadSpriteAnimation

* refactor: removed unused import

* refactor: defined FlipperSprite

* docs: improved SpaceshipWall docs

* refactor: defined SpaceshipRailRampSprite

* refactor: suffixed Component

* refactor: adjusted FlipperSpriteComponent size

* refactor: resized ball

* chore: trace all bodies in sandbox (#157)

* feat: add traceAllBodies method

* chore: update tracing stories

* refactor: use for each

* refactor: convert to mixin

* refactor: simplify mixin

* feat(sandbox): made BasicBallGame traceable

* feat: adjusted ball size
pull/164/head
Alejandro Santiago 4 years ago committed by GitHub
parent fdc3039f72
commit 51b7f478af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -22,36 +22,31 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
layer = Layer.board;
}
/// The size of the [Ball]
static final Vector2 size = Vector2.all(4.5);
/// The size of the [Ball].
static final Vector2 size = Vector2.all(4.13);
/// The base [Color] used to tint this [Ball]
/// The base [Color] used to tint this [Ball].
final Color baseColor;
double _boostTimer = 0;
static const _boostDuration = 2.0;
late SpriteComponent _spriteComponent;
final _BallSpriteComponent _spriteComponent = _BallSpriteComponent();
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(Assets.images.ball.keyName);
final tint = baseColor.withOpacity(0.5);
renderBody = false;
await add(
_spriteComponent = SpriteComponent(
sprite: sprite,
size: size * 1.15,
anchor: Anchor.center,
)..tint(tint),
_spriteComponent..tint(baseColor.withOpacity(0.5)),
);
}
@override
Body createBody() {
final shape = CircleShape()..radius = size.x / 2;
final fixtureDef = FixtureDef(shape)..density = 1;
final bodyDef = BodyDef()
..position = initialPosition
..userData = this
@ -70,7 +65,7 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
/// Allows the [Ball] to be affected by forces.
///
/// If previously [stop]ed, the previous ball's velocity is not kept.
/// If previously [stop]ped, the previous ball's velocity is not kept.
void resume() {
body.setType(BodyType.dynamic);
}
@ -114,3 +109,16 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
_spriteComponent.scale = Vector2.all(scaleFactor);
}
}
class _BallSpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.ball.keyName,
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
}
}

@ -82,23 +82,8 @@ class Baseboard extends BodyComponent with InitialPosition {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
(_side.isLeft)
? Assets.images.baseboard.left.keyName
: Assets.images.baseboard.right.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: Vector2(27.5, 17.9),
anchor: Anchor.center,
position: Vector2(_side.isLeft ? 0.4 : -0.4, 0),
),
);
renderBody = false;
await add(_BaseboardSpriteComponent(side: _side));
}
@override
@ -115,3 +100,23 @@ class Baseboard extends BodyComponent with InitialPosition {
return body;
}
}
class _BaseboardSpriteComponent extends SpriteComponent with HasGameRef {
_BaseboardSpriteComponent({required BoardSide side}) : _side = side;
final BoardSide _side;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
(_side.isLeft)
? Assets.images.baseboard.left.keyName
: Assets.images.baseboard.right.keyName,
);
this.sprite = sprite;
size = sprite.originalSize / 10;
position = Vector2(0.4 * -_side.direction, 0);
anchor = Anchor.center;
}
}

@ -63,23 +63,22 @@ class _BottomBoundary extends BodyComponent with InitialPosition {
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
await add(_BottomBoundarySpriteComponent());
}
}
Future<void> _loadSprite() async {
class _BottomBoundarySpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.boundary.bottom.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(-5.4, 57.4),
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-5.4, 57.4);
}
}
@ -135,22 +134,21 @@ class _OuterBoundary extends BodyComponent with InitialPosition {
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
await add(_OuterBoundarySpriteComponent());
}
}
Future<void> _loadSprite() async {
class _OuterBoundarySpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.boundary.outer.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(-0.2, -1.4),
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-0.2, -1.4);
}
}

@ -81,13 +81,10 @@ class _DinoTopWall extends BodyComponent with InitialPosition {
@override
Body createBody() {
renderBody = false;
final bodyDef = BodyDef()
..userData = this
..position = initialPosition
..type = BodyType.static;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(
(fixture) => body.createFixture(
@ -103,21 +100,22 @@ class _DinoTopWall extends BodyComponent with InitialPosition {
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
await add(_DinoTopWallSpriteComponent());
}
}
Future<void> _loadSprite() async {
class _DinoTopWallSpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.dino.dinoLandTop.keyName,
);
final spriteComponent = SpriteComponent(
sprite: sprite,
size: Vector2(10.6, 27.7),
anchor: Anchor.center,
position: Vector2(27, -28.2),
);
await add(spriteComponent);
this.sprite = sprite;
size = sprite.originalSize / 10;
position = Vector2(27, -28.2);
}
}
@ -182,8 +180,6 @@ class _DinoBottomWall extends BodyComponent with InitialPosition {
@override
Body createBody() {
renderBody = false;
final bodyDef = BodyDef()
..userData = this
..position = initialPosition
@ -204,19 +200,21 @@ class _DinoBottomWall extends BodyComponent with InitialPosition {
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
await add(_DinoBottomWallSpriteComponent());
}
}
Future<void> _loadSprite() async {
class _DinoBottomWallSpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.dino.dinoLandBottom.keyName,
);
final spriteComponent = SpriteComponent(
sprite: sprite,
size: Vector2(15.6, 54.8),
anchor: Anchor.center,
)..position = Vector2(31.7, 18);
await add(spriteComponent);
this.sprite = sprite;
size = sprite.originalSize / 10;
position = Vector2(31.7, 18);
}
}

@ -42,22 +42,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
body.linearVelocity = Vector2(0, _speed);
}
/// Loads the sprite that renders with the [Flipper].
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
(side.isLeft)
? Assets.images.flipper.left.keyName
: Assets.images.flipper.right.keyName,
);
final spriteComponent = SpriteComponent(
sprite: sprite,
size: size,
anchor: Anchor.center,
);
await add(spriteComponent);
}
/// Anchors the [Flipper] to the [RevoluteJoint] that controls its arc motion.
Future<void> _anchorToJoint() async {
final anchor = _FlipperAnchor(flipper: this);
@ -129,10 +113,8 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
await super.onLoad();
renderBody = false;
await Future.wait<void>([
_loadSprite(),
_anchorToJoint(),
]);
await _anchorToJoint();
await add(_FlipperSpriteComponent(side: side));
}
@override
@ -148,6 +130,25 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
}
}
class _FlipperSpriteComponent extends SpriteComponent with HasGameRef {
_FlipperSpriteComponent({required BoardSide side}) : _side = side;
final BoardSide _side;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
(_side.isLeft)
? Assets.images.flipper.left.keyName
: Assets.images.flipper.right.keyName,
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
}
}
/// {@template flipper_anchor}
/// [JointAnchor] positioned at the end of a [Flipper].
///

@ -1,33 +1,17 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template flutter_sign_post}
/// A sign, found in the FlutterForest.
/// A sign, found in the Flutter Forest.
/// {@endtemplate}
// TODO(alestiago): Revisit doc comment if FlutterForest is moved to package.
class FlutterSignPost extends BodyComponent with InitialPosition {
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.flutterSignPost.keyName,
);
final spriteComponent = SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.bottomCenter,
position: Vector2(0.65, 0.45),
);
await add(spriteComponent);
}
@override
Future<void> onLoad() async {
await super.onLoad();
paint = Paint()
..color = Colors.blue.withOpacity(0.5)
..style = PaintingStyle.fill;
await _loadSprite();
renderBody = false;
await add(_FlutterSignPostSpriteComponent());
}
@override
@ -39,3 +23,18 @@ class FlutterSignPost extends BodyComponent with InitialPosition {
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class _FlutterSignPostSpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.flutterSignPost.keyName,
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.bottomCenter;
position = Vector2(0.65, 0.45);
}
}

@ -18,6 +18,9 @@ class Kicker extends BodyComponent with InitialPosition {
required BoardSide side,
}) : _side = side;
/// The size of the [Kicker] body.
static final Vector2 size = Vector2(4.4, 15);
/// Whether the [Kicker] is on the left or right side of the board.
///
/// A [Kicker] with [BoardSide.left] propels the [Ball] to the right,
@ -25,9 +28,6 @@ class Kicker extends BodyComponent with InitialPosition {
/// left.
final BoardSide _side;
/// The size of the [Kicker] body.
static final Vector2 size = Vector2(4.4, 15);
List<FixtureDef> _createFixtureDefs() {
final fixturesDefs = <FixtureDef>[];
final direction = _side.direction;
@ -122,21 +122,28 @@ class Kicker extends BodyComponent with InitialPosition {
Future<void> onLoad() async {
await super.onLoad();
renderBody = false;
await add(_KickerSpriteComponent(side: _side));
}
}
class _KickerSpriteComponent extends SpriteComponent with HasGameRef {
_KickerSpriteComponent({required BoardSide side}) : _side = side;
final BoardSide _side;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
(_side.isLeft)
? Assets.images.kicker.left.keyName
: Assets.images.kicker.right.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: Vector2(8.7, 19),
anchor: Anchor.center,
position: Vector2(0.7 * -_side.direction, -2.2),
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(0.7 * -_side.direction, -2.2);
}
}

@ -115,23 +115,24 @@ class _LaunchRampBase extends BodyComponent with InitialPosition, Layered {
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
await add(_LaunchRampBaseSpriteComponent());
}
}
class _LaunchRampBaseSpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.launchRamp.ramp.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(25.65, 0),
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(25.65, 0);
}
}
@ -192,23 +193,25 @@ class _LaunchRampForegroundRailing extends BodyComponent
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
await add(_LaunchRampForegroundRailingSpriteComponent());
}
}
class _LaunchRampForegroundRailingSpriteComponent extends SpriteComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.launchRamp.foregroundRailing.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(22.8, 0),
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(22.8, 0);
}
}

@ -102,27 +102,9 @@ class AndroidHead extends BodyComponent with InitialPosition, Layered {
@override
Future<void> onLoad() async {
await super.onLoad();
renderBody = false;
final sprite = await gameRef.images.load(
Assets.images.spaceship.bridge.keyName,
);
await add(
SpriteAnimationComponent.fromFrameData(
sprite,
SpriteAnimationData.sequenced(
amount: 72,
amountPerRow: 24,
stepTime: 0.05,
textureSize: Vector2(82, 100),
),
size: Vector2(8.2, 10),
position: Vector2(0, -2),
anchor: Anchor.center,
),
);
await add(_AndroidHeadSpriteAnimation());
}
@override
@ -141,6 +123,29 @@ class AndroidHead extends BodyComponent with InitialPosition, Layered {
}
}
class _AndroidHeadSpriteAnimation extends SpriteAnimationComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final image = await gameRef.images.load(
Assets.images.spaceship.bridge.keyName,
);
size = Vector2(8.2, 10);
position = Vector2(0, -2);
anchor = Anchor.center;
final data = SpriteAnimationData.sequenced(
amount: 72,
amountPerRow: 24,
stepTime: 0.05,
textureSize: size * 10,
);
animation = SpriteAnimation.fromFrameData(image, data);
}
}
/// {@template spaceship_entrance}
/// A sensor [BodyComponent] used to detect when the ball enters the
/// the spaceship area in order to modify its filter data so the ball
@ -228,8 +233,11 @@ class _SpaceshipWallShape extends ChainShape {
/// {@template spaceship_wall}
/// A [BodyComponent] that provides the collision for the wall
/// surrounding the spaceship, with a small opening to allow the
/// [Ball] to get inside the spaceship saucer.
/// surrounding the spaceship.
///
/// It has a small opening to allow the [Ball] to get inside the spaceship
/// saucer.
///
/// It also contains the [SpriteComponent] for the lower wall
/// {@endtemplate}
class SpaceshipWall extends BodyComponent with InitialPosition, Layered {

@ -139,21 +139,23 @@ class _SpaceshipRailRamp extends BodyComponent with InitialPosition, Layered {
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
await add(_SpaceshipRailRampSpriteComponent());
}
}
class _SpaceshipRailRampSpriteComponent extends SpriteComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.rail.main.keyName,
);
final spriteComponent = SpriteComponent(
sprite: sprite,
size: Vector2(17.5, 55.7),
anchor: Anchor.center,
position: Vector2(-29.4, -5.7),
);
await add(spriteComponent);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-29.4, -5.7);
}
}

@ -96,8 +96,6 @@ class _SpaceshipRampBackground extends BodyComponent
@override
Body createBody() {
renderBody = false;
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
@ -111,35 +109,40 @@ class _SpaceshipRampBackground extends BodyComponent
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprites();
}
Future<void> _loadSprites() async {
final spriteRamp = await gameRef.loadSprite(
Assets.images.spaceship.ramp.main.keyName,
);
renderBody = false;
final spriteRampComponent = SpriteComponent(
sprite: spriteRamp,
size: Vector2(38.1, 33.8),
anchor: Anchor.center,
position: Vector2(-12.2, -53.5),
);
await add(_SpaceshipRampBackgroundRailingSpriteComponent());
await add(_SpaceshipRampBackgroundRampSpriteComponent());
}
}
final spriteRailingBg = await gameRef.loadSprite(
class _SpaceshipRampBackgroundRailingSpriteComponent extends SpriteComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.railingBackground.keyName,
);
final spriteRailingBgComponent = SpriteComponent(
sprite: spriteRailingBg,
size: Vector2(38.3, 35.1),
anchor: Anchor.center,
position: spriteRampComponent.position + Vector2(0, -1),
);
this.sprite = sprite;
size = Vector2(38.3, 35.1);
anchor = Anchor.center;
position = Vector2(-12.2, -54.5);
}
}
await addAll([
spriteRailingBgComponent,
spriteRampComponent,
]);
class _SpaceshipRampBackgroundRampSpriteComponent extends SpriteComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.main.keyName,
);
this.sprite = sprite;
size = Vector2(38.3, 35.1);
anchor = Anchor.center;
position = Vector2(-12.2, -543.5);
}
}
@ -196,21 +199,22 @@ class _SpaceshipRampForegroundRailing extends BodyComponent
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprites();
await add(_SpaceshipRampForegroundRalingSpriteComponent());
}
}
Future<void> _loadSprites() async {
final spriteRailingFg = await gameRef.loadSprite(
class _SpaceshipRampForegroundRalingSpriteComponent extends SpriteComponent
with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.railingForeground.keyName,
);
final spriteRailingFgComponent = SpriteComponent(
sprite: spriteRailingFg,
size: Vector2(26.1, 28.3),
anchor: Anchor.center,
position: Vector2(-12.2, -52.5),
);
await add(spriteRailingFgComponent);
this.sprite = sprite;
size = Vector2(26.1, 28.3);
anchor = Anchor.center;
position = Vector2(-12.2, -52.5);
}
}

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BasicBallGame extends BasicGame with TapDetector {
class BasicBallGame extends BasicGame with TapDetector, Traceable {
BasicBallGame({required this.color});
static const info = '''
@ -19,5 +19,6 @@ class BasicBallGame extends BasicGame with TapDetector {
add(
Ball(baseColor: color)..initialPosition = info.eventPosition.game,
);
traceAllBodies();
}
}

@ -12,7 +12,7 @@ void addBallStories(Dashbook dashbook) {
(context) => GameWidget(
game: BasicBallGame(
color: context.colorProperty('color', Colors.blue),
),
)..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('ball/basic.dart'),
info: BasicBallGame.info,

Loading…
Cancel
Save