feat: animate chrome dino (#229)

* feat: included new head and mouth assets

* feat: including sprites

* feat: sized sprites

* feat: included new sprites

* feat: adjusted SpriteAnimationComponent

* feat: adjusted tracing logic

* feat: added Traceable to ChromeDinoGame

* feat: synced dino animation

* refactor: fix crazy rendering

* test: chrome dino

* refactor: dino sandbox

* chore: revert spaceship changes

* chore: move assets for sanbox game

* refactor: move dino walls and bottom boundary

* refactor: move dino for moved dino wall

* test: update goldens

* chore: clean up dino wall fixture defs

* refactor: dino variable and comment fixes

* chore: add todo

* refactor: fix PR nits

* chore: use internal positioning

* refactor: keep positioning

* chore: fix nits and add todo

* fix: update boundaries golden

Co-authored-by: alestiago <dev@alestiago.com>
pull/260/head
Allison Ryan 3 years ago committed by GitHub
parent 8e9ef85dda
commit 97337938d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -18,17 +18,8 @@ class Board extends Component {
final flutterForest = FlutterForest(); final flutterForest = FlutterForest();
// TODO(alestiago): adjust positioning to real design.
// TODO(alestiago): add dino in pinball game.
final dino = ChromeDino()
..initialPosition = Vector2(
BoardDimensions.bounds.center.dx + 25,
BoardDimensions.bounds.center.dy - 10,
);
await addAll([ await addAll([
bottomGroup, bottomGroup,
dino,
flutterForest, flutterForest,
]); ]);
} }

@ -34,8 +34,10 @@ extension PinballGameAssetsX on PinballGame {
images.load( images.load(
components.Assets.images.launchRamp.backgroundRailing.keyName, components.Assets.images.launchRamp.backgroundRailing.keyName,
), ),
images.load(components.Assets.images.dino.dinoLandTop.keyName), images.load(components.Assets.images.dino.bottomWall.keyName),
images.load(components.Assets.images.dino.dinoLandBottom.keyName), images.load(components.Assets.images.dino.topWall.keyName),
images.load(components.Assets.images.dino.animatronic.head.keyName),
images.load(components.Assets.images.dino.animatronic.mouth.keyName),
images.load(components.Assets.images.dash.animatronic.keyName), images.load(components.Assets.images.dash.animatronic.keyName),
images.load(components.Assets.images.dash.bumper.a.active.keyName), images.load(components.Assets.images.dash.bumper.a.active.keyName),
images.load(components.Assets.images.dash.bumper.a.inactive.keyName), images.load(components.Assets.images.dash.bumper.a.inactive.keyName),
@ -81,8 +83,6 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.androidBumper.a.dimmed.keyName), images.load(components.Assets.images.androidBumper.a.dimmed.keyName),
images.load(components.Assets.images.androidBumper.b.lit.keyName), images.load(components.Assets.images.androidBumper.b.lit.keyName),
images.load(components.Assets.images.androidBumper.b.dimmed.keyName), images.load(components.Assets.images.androidBumper.b.dimmed.keyName),
images.load(components.Assets.images.chromeDino.mouth.keyName),
images.load(components.Assets.images.chromeDino.head.keyName),
images.load(components.Assets.images.sparky.computer.top.keyName), images.load(components.Assets.images.sparky.computer.top.keyName),
images.load(components.Assets.images.sparky.computer.base.keyName), images.load(components.Assets.images.sparky.computer.base.keyName),
images.load(components.Assets.images.sparky.animatronic.keyName), images.load(components.Assets.images.sparky.animatronic.keyName),

@ -57,6 +57,7 @@ class PinballGame extends Forge2DGame
await addFromBlueprint(AndroidAcres()); await addFromBlueprint(AndroidAcres());
unawaited(addFromBlueprint(Slingshots())); unawaited(addFromBlueprint(Slingshots()));
unawaited(addFromBlueprint(DinoWalls())); unawaited(addFromBlueprint(DinoWalls()));
await add(ChromeDino()..initialPosition = Vector2(12.3, -6.9));
await add( await add(
GoogleWord( GoogleWord(
position: Vector2( position: Vector2(

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

@ -16,8 +16,6 @@ class $AssetsImagesGen {
$AssetsImagesBallGen get ball => const $AssetsImagesBallGen(); $AssetsImagesBallGen get ball => const $AssetsImagesBallGen();
$AssetsImagesBaseboardGen get baseboard => const $AssetsImagesBaseboardGen(); $AssetsImagesBaseboardGen get baseboard => const $AssetsImagesBaseboardGen();
$AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen(); $AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen();
$AssetsImagesChromeDinoGen get chromeDino =>
const $AssetsImagesChromeDinoGen();
$AssetsImagesDashGen get dash => const $AssetsImagesDashGen(); $AssetsImagesDashGen get dash => const $AssetsImagesDashGen();
$AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen(); $AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen();
$AssetsImagesFlipperGen get flipper => const $AssetsImagesFlipperGen(); $AssetsImagesFlipperGen get flipper => const $AssetsImagesFlipperGen();
@ -97,18 +95,6 @@ class $AssetsImagesBoundaryGen {
const AssetGenImage('assets/images/boundary/outer.png'); const AssetGenImage('assets/images/boundary/outer.png');
} }
class $AssetsImagesChromeDinoGen {
const $AssetsImagesChromeDinoGen();
/// File path: assets/images/chrome_dino/head.png
AssetGenImage get head =>
const AssetGenImage('assets/images/chrome_dino/head.png');
/// File path: assets/images/chrome_dino/mouth.png
AssetGenImage get mouth =>
const AssetGenImage('assets/images/chrome_dino/mouth.png');
}
class $AssetsImagesDashGen { class $AssetsImagesDashGen {
const $AssetsImagesDashGen(); const $AssetsImagesDashGen();
@ -122,13 +108,16 @@ class $AssetsImagesDashGen {
class $AssetsImagesDinoGen { class $AssetsImagesDinoGen {
const $AssetsImagesDinoGen(); const $AssetsImagesDinoGen();
/// File path: assets/images/dino/dino-land-bottom.png $AssetsImagesDinoAnimatronicGen get animatronic =>
AssetGenImage get dinoLandBottom => const $AssetsImagesDinoAnimatronicGen();
const AssetGenImage('assets/images/dino/dino-land-bottom.png');
/// File path: assets/images/dino/bottom-wall.png
AssetGenImage get bottomWall =>
const AssetGenImage('assets/images/dino/bottom-wall.png');
/// File path: assets/images/dino/dino-land-top.png /// File path: assets/images/dino/top-wall.png
AssetGenImage get dinoLandTop => AssetGenImage get topWall =>
const AssetGenImage('assets/images/dino/dino-land-top.png'); const AssetGenImage('assets/images/dino/top-wall.png');
} }
class $AssetsImagesFlipperGen { class $AssetsImagesFlipperGen {
@ -304,6 +293,18 @@ class $AssetsImagesDashBumperGen {
const $AssetsImagesDashBumperMainGen(); const $AssetsImagesDashBumperMainGen();
} }
class $AssetsImagesDinoAnimatronicGen {
const $AssetsImagesDinoAnimatronicGen();
/// File path: assets/images/dino/animatronic/head.png
AssetGenImage get head =>
const AssetGenImage('assets/images/dino/animatronic/head.png');
/// File path: assets/images/dino/animatronic/mouth.png
AssetGenImage get mouth =>
const AssetGenImage('assets/images/dino/animatronic/mouth.png');
}
class $AssetsImagesSpaceshipRailGen { class $AssetsImagesSpaceshipRailGen {
const $AssetsImagesSpaceshipRailGen(); const $AssetsImagesSpaceshipRailGen();

@ -67,7 +67,7 @@ class _BottomBoundarySpriteComponent extends SpriteComponent with HasGameRef {
_BottomBoundarySpriteComponent() _BottomBoundarySpriteComponent()
: super( : super(
anchor: Anchor.center, anchor: Anchor.center,
position: Vector2(-5.4, 55.6), position: Vector2(-5, 55.6),
); );
@override @override

@ -1,31 +1,33 @@
import 'dart:async'; import 'dart:async';
import 'dart:math' as math;
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart' hide Timer; import 'package:flame_forge2d/flame_forge2d.dart' hide Timer;
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template chrome_dino} /// {@template chrome_dino}
/// Dinosaur that gobbles up a [Ball], swivel his head around, and shoots it /// Dino that swivels back and forth, opening its mouth to eat a [Ball].
/// back out. ///
/// Upon eating a [Ball], the dino rotates and spits the [Ball] out in a
/// different direction.
/// {@endtemplate} /// {@endtemplate}
class ChromeDino extends BodyComponent with InitialPosition { class ChromeDino extends BodyComponent with InitialPosition {
/// {@macro chrome_dino} /// {@macro chrome_dino}
ChromeDino() ChromeDino()
: super( : super(
// TODO(alestiago): Remove once sprites are defined.
paint: Paint()..color = Colors.blue,
priority: RenderPriority.dino, priority: RenderPriority.dino,
renderBody: false,
); );
/// The size of the dinosaur mouth. /// The size of the dinosaur mouth.
static final size = Vector2(5, 2.5); static final size = Vector2(5.5, 5);
/// Anchors the [ChromeDino] to the [RevoluteJoint] that controls its arc /// Anchors the [ChromeDino] to the [RevoluteJoint] that controls its arc
/// motion. /// motion.
Future<_ChromeDinoJoint> _anchorToJoint() async { Future<_ChromeDinoJoint> _anchorToJoint() async {
final anchor = _ChromeDinoAnchor(); // TODO(allisonryan0002): try moving to anchor after new body is defined.
final anchor = _ChromeDinoAnchor()
..initialPosition = initialPosition + Vector2(9, -4);
await add(anchor); await add(anchor);
final jointDef = _ChromeDinoAnchorRevoluteJointDef( final jointDef = _ChromeDinoAnchorRevoluteJointDef(
@ -42,9 +44,11 @@ class ChromeDino extends BodyComponent with InitialPosition {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
final joint = await _anchorToJoint(); final joint = await _anchorToJoint();
const framesInAnimation = 98;
const animationFPS = 1 / 24;
await add( await add(
TimerComponent( TimerComponent(
period: 1, period: (framesInAnimation / 2) * animationFPS,
onTick: joint._swivel, onTick: joint._swivel,
repeat: true, repeat: true,
), ),
@ -54,44 +58,17 @@ class ChromeDino extends BodyComponent with InitialPosition {
List<FixtureDef> _createFixtureDefs() { List<FixtureDef> _createFixtureDefs() {
final fixtureDefs = <FixtureDef>[]; final fixtureDefs = <FixtureDef>[];
// TODO(alestiago): Subject to change when sprites are added. // TODO(allisonryan0002): Update this shape to better match sprite.
final box = PolygonShape()..setAsBoxXY(size.x / 2, size.y / 2); final box = PolygonShape()
final fixtureDef = FixtureDef( ..setAsBox(
box, size.x / 2,
density: 999, size.y / 2,
friction: 0.3, initialPosition + Vector2(-4, 2),
restitution: 0.1, -_ChromeDinoJoint._halfSweepingAngle,
isSensor: true, );
); final fixtureDef = FixtureDef(box, density: 1);
fixtureDefs.add(fixtureDef); fixtureDefs.add(fixtureDef);
// FIXME(alestiago): Investigate why adding these fixtures is considered as
// an invalid contact type.
// final upperEdge = EdgeShape()
// ..set(
// Vector2(-size.x / 2, -size.y / 2),
// Vector2(size.x / 2, -size.y / 2),
// );
// final upperEdgeDef = FixtureDef(upperEdge)..density = 0.5;
// fixtureDefs.add(upperEdgeDef);
// final lowerEdge = EdgeShape()
// ..set(
// Vector2(-size.x / 2, size.y / 2),
// Vector2(size.x / 2, size.y / 2),
// );
// final lowerEdgeDef = FixtureDef(lowerEdge)..density = 0.5;
// fixtureDefs.add(lowerEdgeDef);
// final rightEdge = EdgeShape()
// ..set(
// Vector2(size.x / 2, -size.y / 2),
// Vector2(size.x / 2, size.y / 2),
// );
// final rightEdgeDef = FixtureDef(rightEdge)..density = 0.5;
// fixtureDefs.add(rightEdgeDef);
return fixtureDefs; return fixtureDefs;
} }
@ -110,13 +87,18 @@ class ChromeDino extends BodyComponent with InitialPosition {
} }
} }
/// {@template flipper_anchor}
/// [JointAnchor] positioned at the end of a [ChromeDino].
/// {@endtemplate}
class _ChromeDinoAnchor extends JointAnchor { class _ChromeDinoAnchor extends JointAnchor {
/// {@macro flipper_anchor} _ChromeDinoAnchor();
_ChromeDinoAnchor() {
initialPosition = Vector2(ChromeDino.size.x / 2, 0); // TODO(allisonryan0002): if these aren't moved when fixing the rendering, see
// if the joint can be created in onMount to resolve render syncing.
@override
Future<void> onLoad() async {
await super.onLoad();
await addAll([
_ChromeDinoMouthSprite(),
_ChromeDinoHeadSprite(),
]);
} }
} }
@ -135,22 +117,86 @@ class _ChromeDinoAnchorRevoluteJointDef extends RevoluteJointDef {
chromeDino.body.position + anchor.body.position, chromeDino.body.position + anchor.body.position,
); );
enableLimit = true; enableLimit = true;
// TODO(alestiago): Apply design angle value. lowerAngle = -_ChromeDinoJoint._halfSweepingAngle;
const angle = math.pi / 3.5; upperAngle = _ChromeDinoJoint._halfSweepingAngle;
lowerAngle = -angle / 2;
upperAngle = angle / 2;
enableMotor = true; enableMotor = true;
// TODO(alestiago): Tune this values. maxMotorTorque = chromeDino.body.mass * 255;
maxMotorTorque = motorSpeed = chromeDino.body.mass * 30; motorSpeed = 2;
} }
} }
class _ChromeDinoJoint extends RevoluteJoint { class _ChromeDinoJoint extends RevoluteJoint {
_ChromeDinoJoint(_ChromeDinoAnchorRevoluteJointDef def) : super(def); _ChromeDinoJoint(_ChromeDinoAnchorRevoluteJointDef def) : super(def);
static const _halfSweepingAngle = 0.1143;
/// Sweeps the [ChromeDino] up and down repeatedly. /// Sweeps the [ChromeDino] up and down repeatedly.
void _swivel() { void _swivel() {
setMotorSpeed(-motorSpeed); setMotorSpeed(-motorSpeed);
} }
} }
class _ChromeDinoMouthSprite extends SpriteAnimationComponent with HasGameRef {
_ChromeDinoMouthSprite()
: super(
anchor: Anchor(Anchor.center.x + 0.47, Anchor.center.y - 0.29),
angle: _ChromeDinoJoint._halfSweepingAngle,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final image = gameRef.images.fromCache(
Assets.images.dino.animatronic.mouth.keyName,
);
const amountPerRow = 11;
const amountPerColumn = 9;
final textureSize = Vector2(
image.width / amountPerRow,
image.height / amountPerColumn,
);
size = textureSize / 10;
final data = SpriteAnimationData.sequenced(
amount: (amountPerColumn * amountPerRow) - 1,
amountPerRow: amountPerRow,
stepTime: 1 / 24,
textureSize: textureSize,
);
animation = SpriteAnimation.fromFrameData(image, data)..currentIndex = 45;
}
}
class _ChromeDinoHeadSprite extends SpriteAnimationComponent with HasGameRef {
_ChromeDinoHeadSprite()
: super(
anchor: Anchor(Anchor.center.x + 0.47, Anchor.center.y - 0.29),
angle: _ChromeDinoJoint._halfSweepingAngle,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final image = gameRef.images.fromCache(
Assets.images.dino.animatronic.head.keyName,
);
const amountPerRow = 11;
const amountPerColumn = 9;
final textureSize = Vector2(
image.width / amountPerRow,
image.height / amountPerColumn,
);
size = textureSize / 10;
final data = SpriteAnimationData.sequenced(
amount: (amountPerColumn * amountPerRow) - 1,
amountPerRow: amountPerRow,
stepTime: 1 / 24,
textureSize: textureSize,
);
animation = SpriteAnimation.fromFrameData(image, data)..currentIndex = 45;
}
}

@ -35,51 +35,46 @@ class _DinoTopWall extends BodyComponent with InitialPosition {
List<FixtureDef> _createFixtureDefs() { List<FixtureDef> _createFixtureDefs() {
final topStraightShape = EdgeShape() final topStraightShape = EdgeShape()
..set( ..set(
Vector2(28.65, -35.1), Vector2(28.65, -34.3),
Vector2(29.5, -35.1), Vector2(29.5, -34.3),
); );
final topStraightFixtureDef = FixtureDef(topStraightShape);
final topCurveShape = BezierCurveShape( final topCurveShape = BezierCurveShape(
controlPoints: [ controlPoints: [
topStraightShape.vertex1, topStraightShape.vertex1,
Vector2(18.8, -27), Vector2(18.8, -26.2),
Vector2(26.6, -21), Vector2(26.6, -20.2),
], ],
); );
final topCurveFixtureDef = FixtureDef(topCurveShape);
final middleCurveShape = BezierCurveShape( final middleCurveShape = BezierCurveShape(
controlPoints: [ controlPoints: [
topCurveShape.vertices.last, topCurveShape.vertices.last,
Vector2(27.8, -20.1), Vector2(27.8, -19.3),
Vector2(26.8, -19.5), Vector2(26.8, -18.7),
], ],
); );
final middleCurveFixtureDef = FixtureDef(middleCurveShape);
final bottomCurveShape = BezierCurveShape( final bottomCurveShape = BezierCurveShape(
controlPoints: [ controlPoints: [
middleCurveShape.vertices.last, middleCurveShape.vertices.last,
Vector2(23, -15), Vector2(23, -14.2),
Vector2(27, -15), Vector2(27, -14.2),
], ],
); );
final bottomCurveFixtureDef = FixtureDef(bottomCurveShape);
final bottomStraightShape = EdgeShape() final bottomStraightShape = EdgeShape()
..set( ..set(
bottomCurveShape.vertices.last, bottomCurveShape.vertices.last,
Vector2(31, -14.5), Vector2(31, -13.7),
); );
final bottomStraightFixtureDef = FixtureDef(bottomStraightShape);
return [ return [
topStraightFixtureDef, FixtureDef(topStraightShape),
topCurveFixtureDef, FixtureDef(topCurveShape),
middleCurveFixtureDef, FixtureDef(middleCurveShape),
bottomCurveFixtureDef, FixtureDef(bottomCurveShape),
bottomStraightFixtureDef, FixtureDef(bottomStraightShape),
]; ];
} }
@ -109,12 +104,12 @@ class _DinoTopWallSpriteComponent extends SpriteComponent with HasGameRef {
await super.onLoad(); await super.onLoad();
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.dino.dinoLandTop.keyName, Assets.images.dino.topWall.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
position = Vector2(22.8, -38.9); position = Vector2(22.8, -38.1);
} }
} }
@ -131,17 +126,11 @@ class _DinoBottomWall extends BodyComponent with InitialPosition {
); );
List<FixtureDef> _createFixtureDefs() { List<FixtureDef> _createFixtureDefs() {
const restitution = 1.0;
final topStraightShape = EdgeShape() final topStraightShape = EdgeShape()
..set( ..set(
Vector2(32.4, -8.8), Vector2(32.4, -8.8),
Vector2(25, -7.7), Vector2(25, -7.7),
); );
final topStraightFixtureDef = FixtureDef(
topStraightShape,
restitution: restitution,
);
final topLeftCurveShape = BezierCurveShape( final topLeftCurveShape = BezierCurveShape(
controlPoints: [ controlPoints: [
@ -150,36 +139,24 @@ class _DinoBottomWall extends BodyComponent with InitialPosition {
Vector2(29.8, 13.8), Vector2(29.8, 13.8),
], ],
); );
final topLeftCurveFixtureDef = FixtureDef(
topLeftCurveShape,
restitution: restitution,
);
final bottomLeftStraightShape = EdgeShape() final bottomLeftStraightShape = EdgeShape()
..set( ..set(
topLeftCurveShape.vertices.last, topLeftCurveShape.vertices.last,
Vector2(31.9, 44.1), Vector2(31.9, 44.1),
); );
final bottomLeftStraightFixtureDef = FixtureDef(
bottomLeftStraightShape,
restitution: restitution,
);
final bottomStraightShape = EdgeShape() final bottomStraightShape = EdgeShape()
..set( ..set(
bottomLeftStraightShape.vertex2, bottomLeftStraightShape.vertex2,
Vector2(37.8, 44.1), Vector2(37.8, 44.1),
); );
final bottomStraightFixtureDef = FixtureDef(
bottomStraightShape,
restitution: restitution,
);
return [ return [
topStraightFixtureDef, FixtureDef(topStraightShape),
topLeftCurveFixtureDef, FixtureDef(topLeftCurveShape),
bottomLeftStraightFixtureDef, FixtureDef(bottomLeftStraightShape),
bottomStraightFixtureDef, FixtureDef(bottomStraightShape),
]; ];
} }
@ -203,11 +180,11 @@ class _DinoBottomWallSpriteComponent extends SpriteComponent with HasGameRef {
await super.onLoad(); await super.onLoad();
final sprite = Sprite( final sprite = Sprite(
gameRef.images.fromCache( gameRef.images.fromCache(
Assets.images.dino.dinoLandBottom.keyName, Assets.images.dino.bottomWall.keyName,
), ),
); );
this.sprite = sprite; this.sprite = sprite;
size = sprite.originalSize / 10; size = sprite.originalSize / 10;
position = Vector2(23.6, -9.5); position = Vector2(23.8, -9.5);
} }
} }

@ -50,6 +50,7 @@ flutter:
- assets/images/baseboard/ - assets/images/baseboard/
- assets/images/boundary/ - assets/images/boundary/
- assets/images/dino/ - assets/images/dino/
- assets/images/dino/animatronic/
- assets/images/flipper/ - assets/images/flipper/
- assets/images/launch_ramp/ - assets/images/launch_ramp/
- assets/images/dash/ - assets/images/dash/
@ -60,7 +61,6 @@ flutter:
- assets/images/spaceship/rail/ - assets/images/spaceship/rail/
- assets/images/spaceship/ramp/ - assets/images/spaceship/ramp/
- assets/images/spaceship/ramp/arrow/ - assets/images/spaceship/ramp/arrow/
- assets/images/chrome_dino/
- assets/images/kicker/ - assets/images/kicker/
- assets/images/plunger/ - assets/images/plunger/
- assets/images/slingshot/ - assets/images/slingshot/

@ -1,8 +1,22 @@
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class ChromeDinoGame extends Forge2DGame { class ChromeDinoGame extends BallGame {
static const description = 'Shows how a ChromeDino is rendered.'; ChromeDinoGame()
: super(
imagesFileNames: [
Assets.images.dino.animatronic.mouth.keyName,
Assets.images.dino.animatronic.head.keyName,
],
);
static const description = '''
Shows how ChromeDino is rendered.
- Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a ball into the game.
''';
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
@ -10,5 +24,7 @@ class ChromeDinoGame extends Forge2DGame {
camera.followVector2(Vector2.zero()); camera.followVector2(Vector2.zero());
await add(ChromeDino()); await add(ChromeDino());
await traceAllBodies();
} }
} }

@ -4,7 +4,7 @@ import 'package:sandbox/stories/chrome_dino/chrome_dino_game.dart';
void addChromeDinoStories(Dashbook dashbook) { void addChromeDinoStories(Dashbook dashbook) {
dashbook.storiesOf('Chrome Dino').addGame( dashbook.storiesOf('Chrome Dino').addGame(
title: 'Trace', title: 'Traced',
description: ChromeDinoGame.description, description: ChromeDinoGame.description,
gameBuilder: (_) => ChromeDinoGame(), gameBuilder: (_) => ChromeDinoGame(),
); );

@ -20,8 +20,8 @@ class DinoWallGame extends BallGame {
await super.onLoad(); await super.onLoad();
await images.loadAll([ await images.loadAll([
Assets.images.dino.dinoLandTop.keyName, Assets.images.dino.topWall.keyName,
Assets.images.dino.dinoLandBottom.keyName, Assets.images.dino.bottomWall.keyName,
]); ]);
await addFromBlueprint(DinoWalls()); await addFromBlueprint(DinoWalls());

@ -1,13 +1,19 @@
// ignore_for_file: cascade_invocations // ignore_for_file: cascade_invocations
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(Forge2DGame.new); final assets = [
Assets.images.dino.animatronic.mouth.keyName,
Assets.images.dino.animatronic.head.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
group('ChromeDino', () { group('ChromeDino', () {
flameTester.test( flameTester.test(
@ -20,19 +26,84 @@ void main() {
}, },
); );
flameTester.test( flameTester.testGameWidget(
'swivels', 'renders correctly',
(game) async { setUp: (game, tester) async {
// TODO(alestiago): Write golden tests to check the await game.images.loadAll(assets);
// swivel animation. await game.ensureAdd(ChromeDino());
final chromeDino = ChromeDino(); game.camera.followVector2(Vector2.zero());
await game.ensureAdd(chromeDino); await tester.pump();
},
verify: (game, tester) async {
final sweepAnimationDuration = game
.descendants()
.whereType<SpriteAnimationComponent>()
.first
.animation!
.totalDuration() /
2;
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/chrome_dino/up.png'),
);
final previousPosition = chromeDino.body.position.clone(); game.update(sweepAnimationDuration * 0.25);
game.update(64); await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/chrome_dino/middle.png'),
);
expect(chromeDino.body.position, isNot(equals(previousPosition))); game.update(sweepAnimationDuration * 0.25);
await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/chrome_dino/down.png'),
);
}, },
); );
group('swivels', () {
flameTester.test(
'up',
(game) async {
final chromeDino = ChromeDino();
await game.ensureAdd(chromeDino);
game.camera.followVector2(Vector2.zero());
final sweepAnimationDuration = game
.descendants()
.whereType<SpriteAnimationComponent>()
.first
.animation!
.totalDuration() /
2;
game.update(sweepAnimationDuration * 1.5);
expect(chromeDino.body.angularVelocity, isPositive);
},
);
flameTester.test(
'down',
(game) async {
final chromeDino = ChromeDino();
await game.ensureAdd(chromeDino);
game.camera.followVector2(Vector2.zero());
final sweepAnimationDuration = game
.descendants()
.whereType<SpriteAnimationComponent>()
.first
.animation!
.totalDuration() /
2;
game.update(sweepAnimationDuration * 0.5);
expect(chromeDino.body.angularVelocity, isNegative);
},
);
});
}); });
} }

@ -45,6 +45,7 @@ void main() {
); );
}, },
); );
flameTester.test( flameTester.test(
'loads correctly', 'loads correctly',
(game) async { (game) async {

@ -12,8 +12,8 @@ void main() {
group('DinoWalls', () { group('DinoWalls', () {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
final assets = [ final assets = [
Assets.images.dino.dinoLandTop.keyName, Assets.images.dino.topWall.keyName,
Assets.images.dino.dinoLandBottom.keyName, Assets.images.dino.bottomWall.keyName,
]; ];
final flameTester = FlameTester(() => TestGame(assets)); final flameTester = FlameTester(() => TestGame(assets));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

@ -105,18 +105,6 @@ void main() {
expect(flutterForest.length, equals(1)); expect(flutterForest.length, equals(1));
}, },
); );
flameTester.test(
'one ChromeDino',
(game) async {
final board = Board();
await game.ready();
await game.ensureAdd(board);
final chromeDino = board.descendants().whereType<ChromeDino>();
expect(chromeDino.length, equals(1));
},
);
}); });
}); });
} }

@ -27,10 +27,10 @@ void main() {
Assets.images.boundary.bottom.keyName, Assets.images.boundary.bottom.keyName,
Assets.images.boundary.outer.keyName, Assets.images.boundary.outer.keyName,
Assets.images.boundary.outerBottom.keyName, Assets.images.boundary.outerBottom.keyName,
Assets.images.chromeDino.mouth.keyName, Assets.images.dino.animatronic.mouth.keyName,
Assets.images.chromeDino.head.keyName, Assets.images.dino.animatronic.head.keyName,
Assets.images.dino.dinoLandTop.keyName, Assets.images.dino.topWall.keyName,
Assets.images.dino.dinoLandBottom.keyName, Assets.images.dino.bottomWall.keyName,
Assets.images.dash.animatronic.keyName, Assets.images.dash.animatronic.keyName,
Assets.images.dash.bumper.a.active.keyName, Assets.images.dash.bumper.a.active.keyName,
Assets.images.dash.bumper.a.inactive.keyName, Assets.images.dash.bumper.a.inactive.keyName,

Loading…
Cancel
Save