Merge branch 'main' into feat/animate-dino-mouth

pull/229/head
Allison Ryan 3 years ago
commit 7af38e70f6

@ -49,6 +49,7 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.plunger.rocket.keyName),
images.load(components.Assets.images.boundary.bottom.keyName),
images.load(components.Assets.images.boundary.outer.keyName),
images.load(components.Assets.images.boundary.outerBottom.keyName),
images.load(components.Assets.images.spaceship.saucer.keyName),
images.load(components.Assets.images.spaceship.bridge.keyName),
images.load(components.Assets.images.spaceship.ramp.boardOpening.keyName),

@ -2,6 +2,7 @@
import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
@ -135,7 +136,7 @@ class _GameBallsController extends ComponentController<PinballGame>
}
}
class DebugPinballGame extends PinballGame with TapDetector {
class DebugPinballGame extends PinballGame with FPSCounter, TapDetector {
DebugPinballGame({
required PinballTheme theme,
required PinballAudio audio,
@ -150,6 +151,7 @@ class DebugPinballGame extends PinballGame with TapDetector {
Future<void> onLoad() async {
await super.onLoad();
await _loadBackground();
await add(_DebugInformation());
}
// TODO(alestiago): Move to PinballGame once we have the real background
@ -192,3 +194,35 @@ class _DebugGameBallsController extends _GameBallsController {
return noBallsLeft && canBallRespawn;
}
}
class _DebugInformation extends Component with HasGameRef<DebugPinballGame> {
_DebugInformation() : super(priority: RenderPriority.debugInfo);
@override
PositionType get positionType => PositionType.widget;
final _debugTextPaint = TextPaint(
style: const TextStyle(
color: Colors.green,
fontSize: 10,
),
);
final _debugBackgroundPaint = Paint()..color = Colors.white;
@override
void render(Canvas canvas) {
final debugText = [
'FPS: ${gameRef.fps().toStringAsFixed(1)}',
'BALLS: ${gameRef.descendants().whereType<ControlledBall>().length}',
].join(' | ');
final height = _debugTextPaint.measureTextHeight(debugText);
final position = Vector2(0, gameRef.camera.canvasSize.y - height);
canvas.drawRect(
position & Vector2(gameRef.camera.canvasSize.x, height),
_debugBackgroundPaint,
);
_debugTextPaint.render(canvas, debugText, position);
}
}

@ -36,7 +36,7 @@ extension LeaderboardEntryDataX on LeaderboardEntryData {
rank: position.toString(),
playerInitials: playerInitials,
score: score,
character: character.toTheme.character,
character: character.toTheme.leaderboardIcon,
);
}
}

@ -124,7 +124,7 @@ class CharacterImageButton extends StatelessWidget {
),
child: Padding(
padding: const EdgeInsets.all(8),
child: characterTheme.character.image(),
child: characterTheme.icon.image(),
),
),
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@ -84,6 +84,10 @@ class $AssetsImagesBoundaryGen {
AssetGenImage get bottom =>
const AssetGenImage('assets/images/boundary/bottom.png');
/// File path: assets/images/boundary/outer-bottom.png
AssetGenImage get outerBottom =>
const AssetGenImage('assets/images/boundary/outer-bottom.png');
/// File path: assets/images/boundary/outer.png
AssetGenImage get outer =>
const AssetGenImage('assets/images/boundary/outer.png');

@ -13,6 +13,7 @@ class Boundaries extends Blueprint {
components: [
_BottomBoundary(),
_OuterBoundary(),
_OuterBottomBoundarySpriteComponent(),
],
);
}
@ -91,8 +92,10 @@ class _OuterBoundary extends BodyComponent with InitialPosition {
/// {@macro outer_boundary}
_OuterBoundary()
: super(
priority: RenderPriority.outerBoudary,
children: [_OuterBoundarySpriteComponent()],
priority: RenderPriority.outerBoundary,
children: [
_OuterBoundarySpriteComponent(),
],
) {
renderBody = false;
}
@ -157,3 +160,25 @@ class _OuterBoundarySpriteComponent extends SpriteComponent with HasGameRef {
size = sprite.originalSize / 10;
}
}
class _OuterBottomBoundarySpriteComponent extends SpriteComponent
with HasGameRef {
_OuterBottomBoundarySpriteComponent()
: super(
priority: RenderPriority.outerBottomBoundary,
anchor: Anchor.center,
position: Vector2(0, 71),
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.boundary.outerBottom.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
}
}

@ -78,6 +78,7 @@ class _GoogleLetterSprite extends SpriteComponent with HasGameRef {
Future<void> onLoad() async {
await super.onLoad();
// TODO(alestiago): Used cached assets.
final sprite = await gameRef.loadSprite(_path);
this.sprite = sprite;
// TODO(alestiago): Size correctly once the assets are provided.

@ -136,6 +136,7 @@ class _KickerSpriteComponent extends SpriteComponent with HasGameRef {
Future<void> onLoad() async {
await super.onLoad();
// TODO(alestiago): Used cached asset.
final sprite = await gameRef.loadSprite(
(_side.isLeft)
? Assets.images.kicker.left.keyName

@ -148,6 +148,7 @@ class _PlungerSpriteAnimationGroupComponent
Future<void> onLoad() async {
await super.onLoad();
// TODO(alestiago): Used cached images.
final spriteSheet = await gameRef.images.load(
Assets.images.plunger.plunger.keyName,
);

@ -39,7 +39,9 @@ abstract class RenderPriority {
static const int bottomBoundary = _above + dinoBottomWall;
static const int outerBoudary = _above + background;
static const int outerBoundary = _above + background;
static const int outerBottomBoundary = _above + rocket;
// Bottom Group
@ -47,7 +49,7 @@ abstract class RenderPriority {
// Launcher
static const int launchRamp = _above + outerBoudary;
static const int launchRamp = _above + outerBoundary;
static const int launchRampForegroundRailing = _below + ballOnBoard;
@ -113,4 +115,7 @@ abstract class RenderPriority {
// Score Text
static const int scoreText = _above + spaceshipRampForegroundRailing;
// Debug information
static const int debugInfo = _above + scoreText;
}

@ -0,0 +1,36 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
const _path =
'https://github.com/VGVentures/pinball/tree/main/packages/pinball_components/sandbox/lib/stories/';
extension StoryAddGame on Story {
void addGame({
required String title,
required String description,
required Game Function(DashbookContext) gameBuilder,
}) {
final _chapter = Chapter(
title,
(DashbookContext context) {
final game = gameBuilder(context);
if (game is Traceable) {
game.trace = context.boolProperty('Trace', true);
}
return GameWidget(game: game);
},
this,
codeLink: '$_path${name.toPath()}/${title.toPath()}',
info: description,
);
chapters.add(_chapter);
}
}
extension on String {
String toPath() {
return replaceAll(' ', '_')..toLowerCase();
}
}

@ -1,3 +1,3 @@
export 'add_game.dart';
export 'games.dart';
export 'methods.dart';
export 'trace.dart';

@ -5,16 +5,25 @@ import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
abstract class BasicGame extends Forge2DGame {
BasicGame() {
abstract class AssetsGame extends Forge2DGame {
AssetsGame({
List<String>? imagesFileNames,
}) : _imagesFileNames = imagesFileNames {
images.prefix = '';
}
}
abstract class BasicKeyboardGame extends BasicGame
with HasKeyboardHandlerComponents {}
final List<String>? _imagesFileNames;
@override
Future<void> onLoad() async {
await super.onLoad();
if (_imagesFileNames != null) {
await images.loadAll(_imagesFileNames!);
}
}
}
abstract class LineGame extends BasicGame with PanDetector {
abstract class LineGame extends AssetsGame with PanDetector {
Vector2? _lineEnd;
@override

@ -1,3 +0,0 @@
String buildSourceLink(String path) {
return 'https://github.com/VGVentures/pinball/tree/main/packages/pinball_components/sandbox/lib/stories/$path';
}

@ -16,9 +16,6 @@ void main() {
addLayerStories(dashbook);
addEffectsStories(dashbook);
addFlipperStories(dashbook);
addSpaceshipStories(dashbook);
addSpaceshipRampStories(dashbook);
addSpaceshipRailStories(dashbook);
addBaseboardStories(dashbook);
addChromeDinoStories(dashbook);
addDashNestBumperStories(dashbook);
@ -27,7 +24,6 @@ void main() {
addSlingshotStories(dashbook);
addSparkyBumperStories(dashbook);
addAlienZoneStories(dashbook);
addZoomStories(dashbook);
addBoundariesStories(dashbook);
addGoogleWordStories(dashbook);
addLaunchRampStories(dashbook);

@ -4,10 +4,17 @@ import 'package:flame/extensions.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class AlienBumperAGame extends BasicBallGame {
AlienBumperAGame() : super(color: const Color(0xFF0000FF));
static const info = '''
class AlienBumperAGame extends BallGame {
AlienBumperAGame()
: super(
color: const Color(0xFF0000FF),
imagesFileNames: [
Assets.images.alienBumper.a.active.keyName,
Assets.images.alienBumper.a.inactive.keyName,
],
);
static const description = '''
Shows how a AlienBumperA is rendered.
- Activate the "trace" parameter to overlay the body.
@ -17,16 +24,10 @@ class AlienBumperAGame extends BasicBallGame {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.alienBumper.a.active.keyName,
Assets.images.alienBumper.a.inactive.keyName,
]);
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final alienBumperA = AlienBumper.a()
..initialPosition = Vector2(center.x - 20, center.y - 20)
..priority = 1;
await add(alienBumperA);
camera.followVector2(Vector2.zero());
await add(
AlienBumper.a()..priority = 1,
);
await traceAllBodies();
}

@ -4,10 +4,17 @@ import 'package:flame/extensions.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class AlienBumperBGame extends BasicBallGame {
AlienBumperBGame() : super(color: const Color(0xFF0000FF));
static const info = '''
class AlienBumperBGame extends BallGame {
AlienBumperBGame()
: super(
color: const Color(0xFF0000FF),
imagesFileNames: [
Assets.images.alienBumper.b.active.keyName,
Assets.images.alienBumper.b.inactive.keyName,
],
);
static const description = '''
Shows how a AlienBumperB is rendered.
- Activate the "trace" parameter to overlay the body.
@ -17,16 +24,10 @@ class AlienBumperBGame extends BasicBallGame {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.alienBumper.b.active.keyName,
Assets.images.alienBumper.b.inactive.keyName,
]);
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final alienBumperB = AlienBumper.b()
..initialPosition = Vector2(center.x - 10, center.y + 10)
..priority = 1;
await add(alienBumperB);
camera.followVector2(Vector2.zero());
await add(
AlienBumper.b()..priority = 1,
);
await traceAllBodies();
}

@ -6,8 +6,8 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/common/common.dart';
class BasicSpaceshipGame extends BasicGame with TapDetector {
static const info = '''
class SpaceshipGame extends AssetsGame with TapDetector {
static const description = '''
Shows how a Spaceship works.
- Tap anywhere on the screen to spawn a Ball into the game.
@ -18,10 +18,10 @@ class BasicSpaceshipGame extends BasicGame with TapDetector {
await super.onLoad();
camera.followVector2(Vector2.zero());
unawaited(
addFromBlueprint(Spaceship(position: Vector2.zero())),
await addFromBlueprint(
Spaceship(position: Vector2.zero()),
);
await ready();
}
@override

@ -6,7 +6,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SpaceshipRailGame extends BasicBallGame {
class SpaceshipRailGame extends BallGame {
SpaceshipRailGame()
: super(
color: Colors.blue,
@ -14,7 +14,7 @@ class SpaceshipRailGame extends BasicBallGame {
ballLayer: Layer.spaceshipExitRail,
);
static const info = '''
static const description = '''
Shows how SpaceshipRail are rendered.
- Activate the "trace" parameter to overlay the body.
@ -26,10 +26,8 @@ class SpaceshipRailGame extends BasicBallGame {
await super.onLoad();
camera.followVector2(Vector2(-30, -10));
final spaceshipRail = SpaceshipRail();
unawaited(addFromBlueprint(spaceshipRail));
await addFromBlueprint(SpaceshipRail());
await ready();
await traceAllBodies();
}
}

@ -7,15 +7,27 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SpaceshipRampGame extends BasicBallGame with KeyboardEvents {
class SpaceshipRampGame extends BallGame with KeyboardEvents {
SpaceshipRampGame()
: super(
color: Colors.blue,
ballPriority: RenderPriority.ballOnSpaceshipRamp,
ballLayer: Layer.spaceshipEntranceRamp,
imagesFileNames: [
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
],
);
static const info = '''
static const description = '''
Shows how SpaceshipRamp is rendered.
- Activate the "trace" parameter to overlay the body.
@ -29,22 +41,10 @@ class SpaceshipRampGame extends BasicBallGame with KeyboardEvents {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
]);
_spaceshipRamp = SpaceshipRamp();
await addFromBlueprint(_spaceshipRamp);
camera.followVector2(Vector2(-12, -50));
await addFromBlueprint(
_spaceshipRamp = SpaceshipRamp(),
);
await traceAllBodies();
}

@ -1,25 +1,36 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/alien_zone/alien_bumper_a_game.dart';
import 'package:sandbox/stories/alien_zone/alien_bumper_b_game.dart';
import 'package:sandbox/stories/alien_zone/spaceship_game.dart';
import 'package:sandbox/stories/alien_zone/spaceship_rail_game.dart';
import 'package:sandbox/stories/alien_zone/spaceship_ramp_game.dart';
void addAlienZoneStories(Dashbook dashbook) {
dashbook.storiesOf('Alien Zone')
..add(
'Alien Bumper A',
(context) => GameWidget(
game: AlienBumperAGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('alien_zone/alien_bumper_a.dart'),
info: AlienBumperAGame.info,
..addGame(
title: 'Alien Bumper A',
description: AlienBumperAGame.description,
gameBuilder: (_) => AlienBumperAGame(),
)
..add(
'Alien Bumper B',
(context) => GameWidget(
game: AlienBumperBGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('alien_zone/alien_bumper_b.dart'),
info: AlienBumperAGame.info,
..addGame(
title: 'Alien Bumper B',
description: AlienBumperBGame.description,
gameBuilder: (_) => AlienBumperBGame(),
)
..addGame(
title: 'Spaceship',
description: SpaceshipGame.description,
gameBuilder: (_) => SpaceshipGame(),
)
..addGame(
title: 'Spaceship Rail',
description: SpaceshipRailGame.description,
gameBuilder: (_) => SpaceshipRailGame(),
)
..addGame(
title: 'Spaceship Ramp',
description: SpaceshipRampGame.description,
gameBuilder: (_) => SpaceshipRampGame(),
);
}

@ -1,21 +1,22 @@
import 'package:flame/components.dart';
import 'package:flame/input.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);
class BackboardGameOverGame extends AssetsGame
with HasKeyboardHandlerComponents {
BackboardGameOverGame(this.score, this.character)
: super(
imagesFileNames: characterIconPaths.values.toList(),
);
static const info = '''
Simple example showing the game over mode of the backboard.
static const description = '''
Shows how the Backboard in game over mode is rendered.
- 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,
@ -23,14 +24,16 @@ class BackboardGameOverGame extends BasicKeyboardGame {
'Dino': Assets.images.dino.leaderboardIcon.keyName,
};
final int score;
final String character;
@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),

@ -2,9 +2,14 @@ import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BackboardWaitingGame extends BasicGame {
static const info = '''
Simple example showing the waiting mode of the backboard.
class BackboardWaitingGame extends AssetsGame {
BackboardWaitingGame()
: super(
imagesFileNames: [],
);
static const description = '''
Shows how the Backboard in waiting mode is rendered.
''';
@override
@ -13,7 +18,8 @@ class BackboardWaitingGame extends BasicGame {
..followVector2(Vector2.zero())
..zoom = 5;
final backboard = Backboard.waiting(position: Vector2(0, 20));
await add(backboard);
await add(
Backboard.waiting(position: Vector2(0, 20)),
);
}
}

@ -1,32 +1,25 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/backboard/backboard_game_over_game.dart';
import 'package:sandbox/stories/backboard/backboard_waiting_game.dart';
void addBackboardStories(Dashbook dashbook) {
dashbook.storiesOf('Backboard')
..add(
'Waiting mode',
(context) => GameWidget(
game: BackboardWaitingGame(),
),
codeLink: buildSourceLink('backboard/waiting.dart'),
info: BackboardWaitingGame.info,
..addGame(
title: 'Waiting',
description: BackboardWaitingGame.description,
gameBuilder: (_) => BackboardWaitingGame(),
)
..add(
'Game over',
(context) => GameWidget(
game: BackboardGameOverGame(
context.numberProperty('Score', 9000000000).toInt(),
context.listProperty(
'Character',
BackboardGameOverGame.characterIconPaths.keys.first,
BackboardGameOverGame.characterIconPaths.keys.toList(),
),
..addGame(
title: 'Game over',
description: BackboardGameOverGame.description,
gameBuilder: (context) => BackboardGameOverGame(
context.numberProperty('Score', 9000000000).toInt(),
context.listProperty(
'Character',
BackboardGameOverGame.characterIconPaths.keys.first,
BackboardGameOverGame.characterIconPaths.keys.toList(),
),
),
codeLink: buildSourceLink('backboard/game_over.dart'),
info: BackboardGameOverGame.info,
);
}

@ -4,7 +4,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BallBoosterGame extends LineGame {
static const info = '''
static const description = '''
Shows how a Ball with a boost works.
- Drag to launch a boosted Ball.

@ -3,14 +3,20 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BasicBallGame extends BasicGame with TapDetector, Traceable {
BasicBallGame({
class BallGame extends AssetsGame with TapDetector, Traceable {
BallGame({
this.color = Colors.blue,
this.ballPriority = 0,
this.ballLayer = Layer.all,
});
List<String>? imagesFileNames,
}) : super(
imagesFileNames: [
Assets.images.ball.ball.keyName,
if (imagesFileNames != null) ...imagesFileNames,
],
);
static const info = '''
static const description = '''
Shows how a Ball works.
- Tap anywhere on the screen to spawn a ball into the game.

@ -1,5 +1,4 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/ball_booster_game.dart';
@ -7,22 +6,16 @@ import 'package:sandbox/stories/ball/basic_ball_game.dart';
void addBallStories(Dashbook dashbook) {
dashbook.storiesOf('Ball')
..add(
'Basic',
(context) => GameWidget(
game: BasicBallGame(
color: context.colorProperty('color', Colors.blue),
)..trace = context.boolProperty('Trace', true),
..addGame(
title: 'Colored',
description: BallGame.description,
gameBuilder: (context) => BallGame(
color: context.colorProperty('color', Colors.blue),
),
codeLink: buildSourceLink('ball/basic.dart'),
info: BasicBallGame.info,
)
..add(
'Booster',
(context) => GameWidget(
game: BallBoosterGame(),
),
codeLink: buildSourceLink('ball/ball_booster.dart'),
info: BallBoosterGame.info,
..addGame(
title: 'Booster',
description: BallBoosterGame.description,
gameBuilder: (context) => BallBoosterGame(),
);
}

@ -1,10 +1,17 @@
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 = '''
class BaseboardGame extends BallGame {
BaseboardGame()
: super(
imagesFileNames: [
Assets.images.baseboard.left.keyName,
Assets.images.baseboard.right.keyName,
],
);
static const description = '''
Shows how the Baseboards are rendered.
- Activate the "trace" parameter to overlay the body.
@ -15,22 +22,14 @@ class BaseboardGame extends BasicBallGame with Traceable {
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,
Baseboard(side: BoardSide.left)
..initialPosition = center - Vector2(25, 0)
..priority = 1,
Baseboard(side: BoardSide.right)
..initialPosition = center + Vector2(25, 0)
..priority = 1,
]);
await traceAllBodies();

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/baseboard/baseboard_game.dart';
void addBaseboardStories(Dashbook dashbook) {
dashbook.storiesOf('Baseboard').add(
'Basic',
(context) => GameWidget(
game: BaseboardGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('baseboard_game/basic.dart'),
info: BaseboardGame.info,
dashbook.storiesOf('Baseboard').addGame(
title: 'Traced',
description: BaseboardGame.description,
gameBuilder: (_) => BaseboardGame(),
);
}

@ -1,11 +1,19 @@
import 'package:flame/extensions.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class BoundariesGame extends BasicBallGame with Traceable {
static const info = '''
class BoundariesGame extends BallGame {
BoundariesGame()
: super(
imagesFileNames: [
Assets.images.boundary.outer.keyName,
Assets.images.boundary.outerBottom.keyName,
Assets.images.boundary.bottom.keyName,
],
);
static const description = '''
Shows how Boundaries are rendered.
- Activate the "trace" parameter to overlay the body.
@ -16,18 +24,11 @@ class BoundariesGame extends BasicBallGame with Traceable {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.boundary.outer.keyName,
Assets.images.boundary.bottom.keyName,
]);
await addFromBlueprint(Boundaries());
await ready();
camera
..followVector2(Vector2.zero())
..zoom = 6;
await addFromBlueprint(Boundaries());
await ready();
await traceAllBodies();
}
}

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/boundaries/boundaries_game.dart';
void addBoundariesStories(Dashbook dashbook) {
dashbook.storiesOf('Boundaries').add(
'Basic',
(context) => GameWidget(
game: BoundariesGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('boundaries_game/basic.dart'),
info: BoundariesGame.info,
dashbook.storiesOf('Boundaries').addGame(
title: 'Traced',
description: BoundariesGame.description,
gameBuilder: (_) => BoundariesGame(),
);
}

@ -2,7 +2,7 @@ import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class ChromeDinoGame extends BasicGame with Traceable {
class ChromeDinoGame extends AssetsGame with Traceable {
static const info = 'Shows how a ChromeDino is rendered.';
@override

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/chrome_dino/chrome_dino_game.dart';
void addChromeDinoStories(Dashbook dashbook) {
dashbook.storiesOf('Chrome Dino').add(
'Basic',
(context) => GameWidget(
game: ChromeDinoGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('chrome_dino/basic.dart'),
info: ChromeDinoGame.info,
dashbook.storiesOf('Chrome Dino').addGame(
title: 'Traced',
description: ChromeDinoGame.description,
gameBuilder: (_) => ChromeDinoGame(),
);
}

@ -3,8 +3,8 @@ import 'package:flame/input.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BasicCameraZoomGame extends BasicGame with TapDetector {
static const info = '''
class CameraZoomGame extends AssetsGame with TapDetector {
static const description = '''
Shows how CameraZoom can be used.
- Tap to zoom in/out.

@ -3,7 +3,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class FireEffectGame extends LineGame {
static const info = '''
static const description = '''
Shows how the FireEffect renders.
- Drag a line to define the trail direction.

@ -1,13 +1,18 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/effects/camera_zoom_game.dart';
import 'package:sandbox/stories/effects/fire_effect_game.dart';
void addEffectsStories(Dashbook dashbook) {
dashbook.storiesOf('Effects').add(
'Fire Effect',
(context) => GameWidget(game: FireEffectGame()),
codeLink: buildSourceLink('effects/fire_effect.dart'),
info: FireEffectGame.info,
);
dashbook.storiesOf('Effects')
..addGame(
title: 'Fire',
description: FireEffectGame.description,
gameBuilder: (_) => FireEffectGame(),
)
..addGame(
title: 'CameraZoom',
description: CameraZoomGame.description,
gameBuilder: (_) => CameraZoomGame(),
);
}

@ -2,12 +2,19 @@ import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class FlipperGame extends BasicBallGame with KeyboardEvents, Traceable {
static const info = '''
class FlipperGame extends BallGame with KeyboardEvents {
FlipperGame()
: super(
imagesFileNames: [
Assets.images.flipper.left.keyName,
Assets.images.flipper.right.keyName,
],
);
static const description = '''
Shows how Flippers are rendered.
- Activate the "trace" parameter to overlay the body.
@ -33,21 +40,12 @@ class FlipperGame extends BasicBallGame with KeyboardEvents, Traceable {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.flipper.left.keyName,
Assets.images.flipper.right.keyName,
]);
final center = screenToWorld(camera.viewport.canvasSize! / 2);
leftFlipper = Flipper(side: BoardSide.left)
..initialPosition = center - Vector2(Flipper.size.x, 0);
rightFlipper = Flipper(side: BoardSide.right)
..initialPosition = center + Vector2(Flipper.size.x, 0);
await addAll([
leftFlipper,
rightFlipper,
leftFlipper = Flipper(side: BoardSide.left)
..initialPosition = center - Vector2(Flipper.size.x, 0),
rightFlipper = Flipper(side: BoardSide.right)
..initialPosition = center + Vector2(Flipper.size.x, 0),
]);
await traceAllBodies();

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/flipper/flipper_game.dart';
void addFlipperStories(Dashbook dashbook) {
dashbook.storiesOf('Flipper').add(
'Basic',
(context) => GameWidget(
game: FlipperGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('flipper/basic.dart'),
info: FlipperGame.info,
dashbook.storiesOf('Flipper').addGame(
title: 'Traced',
description: FlipperGame.description,
gameBuilder: (_) => FlipperGame(),
);
}

@ -2,11 +2,18 @@ import 'dart:async';
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 BigDashNestBumperGame extends BasicBallGame with Traceable {
static const info = '''
class BigDashNestBumperGame extends BallGame {
BigDashNestBumperGame()
: super(
imagesFileNames: [
Assets.images.dash.bumper.main.active.keyName,
Assets.images.dash.bumper.main.inactive.keyName,
],
);
static const description = '''
Shows how a BigDashNestBumper is rendered.
- Activate the "trace" parameter to overlay the body.
@ -16,13 +23,10 @@ class BigDashNestBumperGame extends BasicBallGame with Traceable {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.dash.bumper.main.active.keyName,
Assets.images.dash.bumper.main.inactive.keyName,
]);
camera.followVector2(Vector2.zero());
await add(DashNestBumper.main()..priority = 1);
await add(
DashNestBumper.main()..priority = 1,
);
await traceAllBodies();
}
}

@ -2,11 +2,20 @@ import 'dart:async';
import 'package:flame/input.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SignpostGame extends BasicBallGame with Traceable, TapDetector {
static const info = '''
class SignpostGame extends BallGame {
SignpostGame()
: super(
imagesFileNames: [
Assets.images.signpost.inactive.keyName,
Assets.images.signpost.active1.keyName,
Assets.images.signpost.active2.keyName,
Assets.images.signpost.active3.keyName,
],
);
static const description = '''
Shows how a Signpost is rendered.
- Activate the "trace" parameter to overlay the body.
@ -17,13 +26,6 @@ class SignpostGame extends BasicBallGame with Traceable, TapDetector {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.signpost.inactive.keyName,
Assets.images.signpost.active1.keyName,
Assets.images.signpost.active2.keyName,
Assets.images.signpost.active3.keyName,
]);
camera.followVector2(Vector2.zero());
await add(Signpost());
await traceAllBodies();

@ -2,11 +2,18 @@ import 'dart:async';
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 SmallDashNestBumperAGame extends BasicBallGame with Traceable {
static const info = '''
class SmallDashNestBumperAGame extends BallGame {
SmallDashNestBumperAGame()
: super(
imagesFileNames: [
Assets.images.dash.bumper.a.active.keyName,
Assets.images.dash.bumper.a.inactive.keyName,
],
);
static const description = '''
Shows how a SmallDashNestBumper ("a") is rendered.
- Activate the "trace" parameter to overlay the body.
@ -16,11 +23,6 @@ class SmallDashNestBumperAGame extends BasicBallGame with Traceable {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.dash.bumper.a.active.keyName,
Assets.images.dash.bumper.a.inactive.keyName,
]);
camera.followVector2(Vector2.zero());
await add(DashNestBumper.a()..priority = 1);
await traceAllBodies();

@ -2,11 +2,18 @@ import 'dart:async';
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 SmallDashNestBumperBGame extends BasicBallGame with Traceable {
static const info = '''
class SmallDashNestBumperBGame extends BallGame {
SmallDashNestBumperBGame()
: super(
imagesFileNames: [
Assets.images.dash.bumper.b.active.keyName,
Assets.images.dash.bumper.b.inactive.keyName,
],
);
static const description = '''
Shows how a SmallDashNestBumper ("b") is rendered.
- Activate the "trace" parameter to overlay the body.
@ -16,11 +23,6 @@ class SmallDashNestBumperBGame extends BasicBallGame with Traceable {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.dash.bumper.b.active.keyName,
Assets.images.dash.bumper.b.inactive.keyName,
]);
camera.followVector2(Vector2.zero());
await add(DashNestBumper.b()..priority = 1);
await traceAllBodies();

@ -1,5 +1,4 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/flutter_forest/big_dash_nest_bumper_game.dart';
import 'package:sandbox/stories/flutter_forest/signpost_game.dart';
@ -8,39 +7,24 @@ import 'package:sandbox/stories/flutter_forest/small_dash_nest_bumper_b_game.dar
void addDashNestBumperStories(Dashbook dashbook) {
dashbook.storiesOf('Flutter Forest')
..add(
'Signpost',
(context) => GameWidget(
game: SignpostGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('flutter_forest/signpost.dart'),
info: SignpostGame.info,
..addGame(
title: 'Signpost',
description: SignpostGame.description,
gameBuilder: (_) => SignpostGame(),
)
..add(
'Big Dash Nest Bumper',
(context) => GameWidget(
game: BigDashNestBumperGame()
..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('flutter_forest/big_dash_nest_bumper.dart'),
info: BigDashNestBumperGame.info,
..addGame(
title: 'Big Dash Nest Bumper',
description: BigDashNestBumperGame.description,
gameBuilder: (_) => BigDashNestBumperGame(),
)
..add(
'Small Dash Nest Bumper A',
(context) => GameWidget(
game: SmallDashNestBumperAGame()
..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('flutter_forest/small_dash_nest_bumper_a.dart'),
info: SmallDashNestBumperAGame.info,
..addGame(
title: 'Small Dash Nest Bumper A',
description: SmallDashNestBumperAGame.description,
gameBuilder: (_) => SmallDashNestBumperAGame(),
)
..add(
'Small Dash Nest Bumper B',
(context) => GameWidget(
game: SmallDashNestBumperBGame()
..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('flutter_forest/small_dash_nest_bumper_b.dart'),
info: SmallDashNestBumperBGame.info,
..addGame(
title: 'Small Dash Nest Bumper B',
description: SmallDashNestBumperBGame.description,
gameBuilder: (_) => SmallDashNestBumperBGame(),
);
}

@ -5,10 +5,10 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class GoogleLetterGame extends BasicBallGame {
class GoogleLetterGame extends BallGame {
GoogleLetterGame() : super(color: const Color(0xFF009900));
static const info = '''
static const description = '''
Shows how a GoogleLetter is rendered.
- Tap anywhere on the screen to spawn a ball into the game.

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/google_word/google_letter_game.dart';
void addGoogleWordStories(Dashbook dashbook) {
dashbook.storiesOf('Google Word').add(
'Letter',
(context) => GameWidget(
game: GoogleLetterGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('google_word/letter.dart'),
info: GoogleLetterGame.info,
dashbook.storiesOf('Google Word').addGame(
title: 'Letter 0',
description: GoogleLetterGame.description,
gameBuilder: (_) => GoogleLetterGame(),
);
}

@ -1,10 +1,9 @@
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 KickerGame extends BasicBallGame with Traceable {
static const info = '''
class KickerGame extends BallGame {
static const description = '''
Shows how Kickers are rendered.
- Activate the "trace" parameter to overlay the body.
@ -16,14 +15,14 @@ class KickerGame extends BasicBallGame with Traceable {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final leftKicker = Kicker(side: BoardSide.left)
..initialPosition = Vector2(center.x - (Kicker.size.x * 2), center.y);
await add(leftKicker);
final rightKicker = Kicker(side: BoardSide.right)
..initialPosition = Vector2(center.x + (Kicker.size.x * 2), center.y);
await add(rightKicker);
await addAll(
[
Kicker(side: BoardSide.left)
..initialPosition = Vector2(center.x - (Kicker.size.x * 2), center.y),
Kicker(side: BoardSide.right)
..initialPosition = Vector2(center.x + (Kicker.size.x * 2), center.y),
],
);
await traceAllBodies();
}

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/kicker/kicker_game.dart';
void addKickerStories(Dashbook dashbook) {
dashbook.storiesOf('Kickers').add(
'Basic',
(context) => GameWidget(
game: KickerGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('kicker_game/basic.dart'),
info: KickerGame.info,
dashbook.storiesOf('Kickers').addGame(
title: 'Traced',
description: KickerGame.description,
gameBuilder: (_) => KickerGame(),
);
}

@ -6,7 +6,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class LaunchRampGame extends BasicBallGame {
class LaunchRampGame extends BallGame {
LaunchRampGame()
: super(
color: Colors.blue,
@ -14,7 +14,7 @@ class LaunchRampGame extends BasicBallGame {
ballLayer: Layer.launcher,
);
static const info = '''
static const description = '''
Shows how LaunchRamp are rendered.
- Activate the "trace" parameter to overlay the body.
@ -28,10 +28,8 @@ class LaunchRampGame extends BasicBallGame {
camera
..followVector2(Vector2(0, 0))
..zoom = 7.5;
final launchRamp = LaunchRamp();
unawaited(addFromBlueprint(launchRamp));
await addFromBlueprint(LaunchRamp());
await ready();
await traceAllBodies();
}
}

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/launch_ramp/launch_ramp_game.dart';
void addLaunchRampStories(Dashbook dashbook) {
dashbook.storiesOf('LaunchRamp').add(
'Basic',
(context) => GameWidget(
game: LaunchRampGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('launch_ramp/basic.dart'),
info: LaunchRampGame.info,
dashbook.storiesOf('LaunchRamp').addGame(
title: 'Traced',
description: LaunchRampGame.description,
gameBuilder: (_) => LaunchRampGame(),
);
}

@ -2,36 +2,35 @@ import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class BasicLayerGame extends BasicGame with TapDetector {
BasicLayerGame({required this.color});
static const info = '''
class LayerGame extends BallGame with TapDetector {
static const description = '''
Shows how Layers work when a Ball hits other components.
- Tap anywhere on the screen to spawn a Ball into the game.
''';
final Color color;
@override
Future<void> onLoad() async {
await add(BigSquare()..initialPosition = Vector2(30, -40));
await add(SmallSquare()..initialPosition = Vector2(50, -40));
await add(UnlayeredSquare()..initialPosition = Vector2(60, -40));
}
@override
void onTapUp(TapUpInfo info) {
add(
Ball(baseColor: color)..initialPosition = info.eventPosition.game,
await addAll(
[
_BigSquare()..initialPosition = Vector2(30, -40),
_SmallSquare()..initialPosition = Vector2(50, -40),
_UnlayeredSquare()..initialPosition = Vector2(60, -40),
],
);
}
}
class BigSquare extends BodyComponent with InitialPosition, Layered {
BigSquare() {
class _BigSquare extends BodyComponent with InitialPosition, Layered {
_BigSquare()
: super(
children: [
_UnlayeredSquare()..initialPosition = Vector2.all(4),
_SmallSquare()..initialPosition = Vector2.all(-4),
],
) {
paint = Paint()
..color = const Color.fromARGB(255, 8, 218, 241)
..style = PaintingStyle.stroke;
@ -42,27 +41,13 @@ class BigSquare extends BodyComponent with InitialPosition, Layered {
Body createBody() {
final shape = PolygonShape()..setAsBoxXY(16, 16);
final fixtureDef = FixtureDef(shape);
final bodyDef = BodyDef()..position = initialPosition;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
@override
Future<void> onLoad() async {
await super.onLoad();
await addAll(
[
UnlayeredSquare()..initialPosition = Vector2.all(4),
SmallSquare()..initialPosition = Vector2.all(-4),
],
);
}
}
class SmallSquare extends BodyComponent with InitialPosition, Layered {
SmallSquare() {
class _SmallSquare extends BodyComponent with InitialPosition, Layered {
_SmallSquare() {
paint = Paint()
..color = const Color.fromARGB(255, 27, 241, 8)
..style = PaintingStyle.stroke;
@ -73,15 +58,13 @@ class SmallSquare extends BodyComponent with InitialPosition, Layered {
Body createBody() {
final shape = PolygonShape()..setAsBoxXY(2, 2);
final fixtureDef = FixtureDef(shape);
final bodyDef = BodyDef()..position = initialPosition;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
class UnlayeredSquare extends BodyComponent with InitialPosition {
UnlayeredSquare() {
class _UnlayeredSquare extends BodyComponent with InitialPosition {
_UnlayeredSquare() {
paint = Paint()
..color = const Color.fromARGB(255, 241, 8, 8)
..style = PaintingStyle.stroke;
@ -91,9 +74,7 @@ class UnlayeredSquare extends BodyComponent with InitialPosition {
Body createBody() {
final shape = PolygonShape()..setAsBoxXY(3, 3);
final fixtureDef = FixtureDef(shape);
final bodyDef = BodyDef()..position = initialPosition;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}

@ -1,18 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/layer/basic_layer_game.dart';
import 'package:sandbox/stories/layer/layer_game.dart';
void addLayerStories(Dashbook dashbook) {
dashbook.storiesOf('Layer').add(
'Layer',
(context) => GameWidget(
game: BasicLayerGame(
color: context.colorProperty('color', Colors.blue),
),
),
codeLink: buildSourceLink('layer/basic.dart'),
info: BasicLayerGame.info,
dashbook.storiesOf('Layer').addGame(
title: 'Example',
description: LayerGame.description,
gameBuilder: (_) => LayerGame(),
);
}

@ -5,10 +5,10 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class PlungerGame extends BasicBallGame with KeyboardEvents, Traceable {
class PlungerGame extends BallGame with KeyboardEvents, Traceable {
PlungerGame() : super(color: const Color(0xFFFF0000));
static const info = '''
static const description = '''
Shows how Plunger is rendered.
- Activate the "trace" parameter to overlay the body.
@ -27,11 +27,10 @@ class PlungerGame extends BasicBallGame with KeyboardEvents, Traceable {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
plunger = Plunger(compressionDistance: 29)
..initialPosition = Vector2(center.x - (Kicker.size.x * 2), center.y);
await add(plunger);
await add(
plunger = Plunger(compressionDistance: 29)
..initialPosition = Vector2(center.x - (Kicker.size.x * 2), center.y),
);
await traceAllBodies();
}

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/plunger/plunger_game.dart';
void addPlungerStories(Dashbook dashbook) {
dashbook.storiesOf('Plunger').add(
'Basic',
(context) => GameWidget(
game: PlungerGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('plunger_game/basic.dart'),
info: PlungerGame.info,
dashbook.storiesOf('Plunger').addGame(
title: 'Traced',
description: PlungerGame.description,
gameBuilder: (_) => PlungerGame(),
);
}

@ -5,8 +5,8 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class ScoreTextBasicGame extends BasicGame with TapDetector {
static const info = '''
class ScoreTextGame extends AssetsGame with TapDetector {
static const description = '''
Simple game to show how score text works,
- Tap anywhere on the screen to spawn an text on the given location.

@ -1,15 +1,11 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/score_text/basic.dart';
import 'package:sandbox/stories/score_text/score_text_game.dart';
void addScoreTextStories(Dashbook dashbook) {
dashbook.storiesOf('ScoreText').add(
'Basic',
(context) => GameWidget(
game: ScoreTextBasicGame(),
),
codeLink: buildSourceLink('score_text/basic.dart'),
info: ScoreTextBasicGame.info,
dashbook.storiesOf('ScoreText').addGame(
title: 'Basic',
description: ScoreTextGame.description,
gameBuilder: (_) => ScoreTextGame(),
);
}

@ -1,11 +1,18 @@
import 'package:flame/extensions.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SlingshotGame extends BasicBallGame with Traceable {
static const info = '''
class SlingshotGame extends BallGame {
SlingshotGame()
: super(
imagesFileNames: [
Assets.images.slingshot.upper.keyName,
Assets.images.slingshot.lower.keyName,
],
);
static const description = '''
Shows how Slingshots are rendered.
- Activate the "trace" parameter to overlay the body.
@ -16,13 +23,9 @@ class SlingshotGame extends BasicBallGame with Traceable {
Future<void> onLoad() async {
await super.onLoad();
await images.loadAll([
Assets.images.slingshot.upper.keyName,
Assets.images.slingshot.lower.keyName,
]);
await addFromBlueprint(Slingshots());
camera.followVector2(Vector2.zero());
await addFromBlueprint(Slingshots());
await ready();
await traceAllBodies();
}
}

@ -1,15 +1,11 @@
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,
dashbook.storiesOf('Slingshots').addGame(
title: 'Traced',
description: SlingshotGame.description,
gameBuilder: (_) => SlingshotGame(),
);
}

@ -1,15 +0,0 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/spaceship/basic_spaceship_game.dart';
void addSpaceshipStories(Dashbook dashbook) {
dashbook.storiesOf('Spaceship').add(
'Basic',
(context) => GameWidget(
game: BasicSpaceshipGame(),
),
codeLink: buildSourceLink('spaceship/basic.dart'),
info: BasicSpaceshipGame.info,
);
}

@ -1,16 +0,0 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/spaceship_rail/spaceship_rail_game.dart';
void addSpaceshipRailStories(Dashbook dashbook) {
dashbook.storiesOf('SpaceshipRail').add(
'Basic',
(context) => GameWidget(
game: SpaceshipRailGame()
..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('spaceship_rail/basic.dart'),
info: SpaceshipRailGame.info,
);
}

@ -1,16 +0,0 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/spaceship_ramp/spaceship_ramp_game.dart';
void addSpaceshipRampStories(Dashbook dashbook) {
dashbook.storiesOf('SpaceshipRamp').add(
'Basic',
(context) => GameWidget(
game: SpaceshipRampGame()
..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('spaceship_ramp/basic.dart'),
info: SpaceshipRampGame.info,
);
}

@ -2,11 +2,10 @@ 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 with Traceable {
static const info = '''
class SparkyBumperGame extends BallGame {
static const description = '''
Shows how a SparkyBumper is rendered.
- Activate the "trace" parameter to overlay the body.

@ -1,15 +1,11 @@
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,
dashbook.storiesOf('Sparky Bumpers').addGame(
title: 'Traced',
description: SparkyBumperGame.description,
gameBuilder: (_) => SparkyBumperGame(),
);
}

@ -13,8 +13,4 @@ export 'layer/stories.dart';
export 'plunger/stories.dart';
export 'score_text/stories.dart';
export 'slingshot/stories.dart';
export 'spaceship/stories.dart';
export 'spaceship_rail/stories.dart';
export 'spaceship_ramp/stories.dart';
export 'sparky_bumper/stories.dart';
export 'zoom/stories.dart';

@ -1,15 +0,0 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/zoom/basic_zoom_game.dart';
void addZoomStories(Dashbook dashbook) {
dashbook.storiesOf('CameraZoom').add(
'Basic',
(context) => GameWidget(
game: BasicCameraZoomGame(),
),
codeLink: buildSourceLink('zoom/basic_zoom_game.dart'),
info: BasicCameraZoomGame.info,
);
}

@ -10,20 +10,24 @@ import '../../helpers/helpers.dart';
void main() {
group('Boundaries', () {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.boundary.outer.keyName,
Assets.images.boundary.outerBottom.keyName,
Assets.images.boundary.bottom.keyName,
];
final tester = FlameTester(TestGame.new);
final flameTester = FlameTester(TestGame.new);
tester.testGameWidget(
flameTester.testGameWidget(
'render correctly',
setUp: (game, tester) async {
await game.images.loadAll(assets);
await game.addFromBlueprint(Boundaries());
await game.ready();
game.camera.followVector2(Vector2.zero());
game.camera.zoom = 3.2;
await tester.pump();
},
verify: (game, tester) async {
await expectLater(

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

@ -29,9 +29,12 @@ void main() {
'loads correctly',
(game) async {
final spaceshipRamp = SpaceshipRamp();
await game.ensureAdd(spaceshipRamp);
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
expect(game.contains(spaceshipRamp), isTrue);
for (final component in spaceshipRamp.components) {
expect(game.contains(component), isTrue);
}
},
);

@ -3,3 +3,4 @@ library pinball_flame;
export 'src/blueprint.dart';
export 'src/component_controller.dart';
export 'src/keyboard_input_controller.dart';
export 'src/sprite_animation.dart';

@ -1,16 +1,13 @@
import 'package:flame/components.dart';
import 'package:flame/game.dart';
// TODO(erickzanardo): Keeping this inside our code base
// so we can experiment with the idea, but this is a
// potential upstream change on Flame.
// TODO(erickzanardo): Keeping this inside our code base so we can experiment
// with the idea, but this is a potential upstream change on Flame.
/// {@template blueprint}
/// A [Blueprint] is a virtual way of grouping [Component]s that are related,
/// but they need to be added directly on the [FlameGame] level.
/// A [Blueprint] is a virtual way of grouping [Component]s that are related.
/// {@endtemplate blueprint}
// TODO(alestiago): refactor with feat/make-blueprint-extend-component.
class Blueprint extends Component {
class Blueprint {
/// {@macro blueprint}
Blueprint({
Iterable<Component>? components,
@ -27,7 +24,7 @@ class Blueprint extends Component {
final List<Component> _components = [];
final List<Component> _blueprints = [];
final List<Blueprint> _blueprints = [];
Future<void> _addToParent(Component parent) async {
await parent.addAll(_components);
@ -37,7 +34,7 @@ class Blueprint extends Component {
List<Component> get components => List.unmodifiable(_components);
/// Returns a copy of the blueprints built by this blueprint.
List<Component> get blueprints => List.unmodifiable(_blueprints);
List<Blueprint> get blueprints => List.unmodifiable(_blueprints);
}
/// Adds helper methods regarding [Blueprint]s to [FlameGame].

@ -0,0 +1,102 @@
// ignore_for_file: public_member_api_docs
import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/image_composition.dart';
import 'package:flutter/material.dart' hide Animation;
/// {@template flame.widgets.sprite_animation_widget}
/// A [StatelessWidget] that renders a [SpriteAnimation].
/// {@endtemplate}
// TODO(arturplaczek): Remove when this PR will be merged.
// https://github.com/flame-engine/flame/pull/1552
class SpriteAnimationWidget extends StatelessWidget {
/// {@macro flame.widgets.sprite_animation_widget}
const SpriteAnimationWidget({
required this.controller,
this.anchor = Anchor.topLeft,
Key? key,
}) : super(key: key);
/// The positioning [Anchor].
final Anchor anchor;
final SpriteAnimationController controller;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (_, __) {
return CustomPaint(
painter: SpritePainter(
controller.animation.getSprite(),
anchor,
),
);
},
);
}
}
class SpriteAnimationController extends AnimationController {
SpriteAnimationController({
required TickerProvider vsync,
required this.animation,
}) : super(vsync: vsync) {
duration = Duration(seconds: animation.totalDuration().ceil());
}
final SpriteAnimation animation;
double? _lastUpdated;
@override
void notifyListeners() {
super.notifyListeners();
final now = DateTime.now().millisecond.toDouble();
final dt = max<double>(0, (now - (_lastUpdated ?? 0)) / 1000);
animation.update(dt);
_lastUpdated = now;
}
}
class SpritePainter extends CustomPainter {
SpritePainter(
this._sprite,
this._anchor, {
double angle = 0,
}) : _angle = angle;
final Sprite _sprite;
final Anchor _anchor;
final double _angle;
@override
bool shouldRepaint(SpritePainter oldDelegate) {
return oldDelegate._sprite != _sprite ||
oldDelegate._anchor != _anchor ||
oldDelegate._angle != _angle;
}
@override
void paint(Canvas canvas, Size size) {
final boxSize = size.toVector2();
final rate = boxSize.clone()..divide(_sprite.srcSize);
final minRate = min(rate.x, rate.y);
final paintSize = _sprite.srcSize * minRate;
final anchorPosition = _anchor.toVector2();
final boxAnchorPosition = boxSize.clone()..multiply(anchorPosition);
final spriteAnchorPosition = anchorPosition..multiply(paintSize);
canvas
..translateVector(boxAnchorPosition..sub(spriteAnchorPosition))
..renderRotated(
_angle,
spriteAnchorPosition,
(canvas) => _sprite.render(canvas, size: paintSize),
);
}
}

@ -0,0 +1,74 @@
import 'package:flame/components.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball_flame/pinball_flame.dart';
class MockSpriteAnimationController extends Mock
implements SpriteAnimationController {}
class MockSpriteAnimation extends Mock implements SpriteAnimation {}
class MockSprite extends Mock implements Sprite {}
// TODO(arturplaczek): Remove when this PR will be merged.
// https://github.com/flame-engine/flame/pull/1552
void main() {
group('PinballSpriteAnimationWidget', () {
late SpriteAnimationController controller;
late SpriteAnimation animation;
late Sprite sprite;
setUp(() {
controller = MockSpriteAnimationController();
animation = MockSpriteAnimation();
sprite = MockSprite();
when(() => controller.animation).thenAnswer((_) => animation);
when(() => animation.totalDuration()).thenAnswer((_) => 1);
when(() => animation.getSprite()).thenAnswer((_) => sprite);
when(() => sprite.srcSize).thenAnswer((_) => Vector2(1, 1));
when(() => sprite.srcSize).thenAnswer((_) => Vector2(1, 1));
});
testWidgets('renders correctly', (tester) async {
await tester.pumpWidget(
SpriteAnimationWidget(
controller: controller,
),
);
await tester.pumpAndSettle();
await tester.pumpAndSettle();
expect(find.byType(SpriteAnimationWidget), findsOneWidget);
});
test('SpriteAnimationController is updating animations', () {
SpriteAnimationController(
vsync: const TestVSync(),
animation: animation,
).notifyListeners();
verify(() => animation.update(any())).called(1);
});
testWidgets('SpritePainter shouldRepaint returns true when Sprite changed',
(tester) async {
final spritePainter = SpritePainter(
sprite,
Anchor.center,
angle: 45,
);
final anotherPainter = SpritePainter(
sprite,
Anchor.center,
angle: 30,
);
expect(spritePainter.shouldRepaint(anotherPainter), isTrue);
});
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

@ -28,6 +28,10 @@ class $AssetsImagesGen {
class $AssetsImagesAndroidGen {
const $AssetsImagesAndroidGen();
/// File path: assets/images/android/animation.png
AssetGenImage get animation =>
const AssetGenImage('assets/images/android/animation.png');
/// File path: assets/images/android/background.png
AssetGenImage get background =>
const AssetGenImage('assets/images/android/background.png');
@ -48,6 +52,10 @@ class $AssetsImagesAndroidGen {
class $AssetsImagesDashGen {
const $AssetsImagesDashGen();
/// File path: assets/images/dash/animation.png
AssetGenImage get animation =>
const AssetGenImage('assets/images/dash/animation.png');
/// File path: assets/images/dash/background.png
AssetGenImage get background =>
const AssetGenImage('assets/images/dash/background.png');
@ -67,6 +75,10 @@ class $AssetsImagesDashGen {
class $AssetsImagesDinoGen {
const $AssetsImagesDinoGen();
/// File path: assets/images/dino/animation.png
AssetGenImage get animation =>
const AssetGenImage('assets/images/dino/animation.png');
/// File path: assets/images/dino/background.png
AssetGenImage get background =>
const AssetGenImage('assets/images/dino/background.png');
@ -86,6 +98,10 @@ class $AssetsImagesDinoGen {
class $AssetsImagesSparkyGen {
const $AssetsImagesSparkyGen();
/// File path: assets/images/sparky/animation.png
AssetGenImage get animation =>
const AssetGenImage('assets/images/sparky/animation.png');
/// File path: assets/images/sparky/background.png
AssetGenImage get background =>
const AssetGenImage('assets/images/sparky/background.png');

@ -14,9 +14,6 @@ class AndroidTheme extends CharacterTheme {
@override
Color get ballColor => Colors.green;
@override
AssetGenImage get character => Assets.images.android.character;
@override
AssetGenImage get background => Assets.images.android.background;
@ -25,4 +22,7 @@ class AndroidTheme extends CharacterTheme {
@override
AssetGenImage get leaderboardIcon => Assets.images.android.leaderboardIcon;
@override
AssetGenImage get animation => Assets.images.android.animation;
}

@ -18,9 +18,6 @@ abstract class CharacterTheme extends Equatable {
/// Ball color for this theme.
Color get ballColor;
/// Asset for the theme character.
AssetGenImage get character;
/// Asset for the background.
AssetGenImage get background;
@ -30,13 +27,16 @@ abstract class CharacterTheme extends Equatable {
/// Icon asset for the leaderboard.
AssetGenImage get leaderboardIcon;
/// Asset for the the idle character animation.
AssetGenImage get animation;
@override
List<Object?> get props => [
name,
ballColor,
character,
background,
icon,
leaderboardIcon,
animation,
];
}

@ -14,9 +14,6 @@ class DashTheme extends CharacterTheme {
@override
Color get ballColor => Colors.blue;
@override
AssetGenImage get character => Assets.images.dash.character;
@override
AssetGenImage get background => Assets.images.dash.background;
@ -25,4 +22,7 @@ class DashTheme extends CharacterTheme {
@override
AssetGenImage get leaderboardIcon => Assets.images.dash.leaderboardIcon;
@override
AssetGenImage get animation => Assets.images.dash.animation;
}

@ -14,9 +14,6 @@ class DinoTheme extends CharacterTheme {
@override
Color get ballColor => Colors.grey;
@override
AssetGenImage get character => Assets.images.dino.character;
@override
AssetGenImage get background => Assets.images.dino.background;
@ -25,4 +22,7 @@ class DinoTheme extends CharacterTheme {
@override
AssetGenImage get leaderboardIcon => Assets.images.dino.leaderboardIcon;
@override
AssetGenImage get animation => Assets.images.dino.animation;
}

@ -14,9 +14,6 @@ class SparkyTheme extends CharacterTheme {
@override
String get name => 'Sparky';
@override
AssetGenImage get character => Assets.images.sparky.character;
@override
AssetGenImage get background => Assets.images.sparky.background;
@ -25,4 +22,7 @@ class SparkyTheme extends CharacterTheme {
@override
AssetGenImage get leaderboardIcon => Assets.images.sparky.leaderboardIcon;
@override
AssetGenImage get animation => Assets.images.sparky.animation;
}

@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "39.0.0"
version: "31.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
version: "2.8.0"
args:
dependency: transitive
description:
@ -71,6 +71,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
clock:
dependency: transitive
description:
@ -314,7 +321,7 @@ packages:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
version: "0.6.3"
json_annotation:
dependency: transitive
description:
@ -349,7 +356,7 @@ packages:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
version: "0.1.3"
meta:
dependency: transitive
description:
@ -412,7 +419,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.0"
path_provider:
dependency: transitive
description:
@ -585,7 +592,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.8.1"
stack_trace:
dependency: transitive
description:
@ -627,21 +634,21 @@ packages:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.21.1"
version: "1.19.5"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
version: "0.4.8"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.13"
version: "0.4.9"
typed_data:
dependency: transitive
description:
@ -662,7 +669,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.1"
very_good_analysis:
dependency: "direct dev"
description:

@ -27,8 +27,8 @@ void main() {
group('SparkyFireZone', () {
flameTester.test('loads correctly', (game) async {
final sparkyFireZone = SparkyFireZone();
await game.ensureAdd(sparkyFireZone);
await game.addFromBlueprint(SparkyFireZone());
await game.ready();
});
group('loads', () {

@ -52,6 +52,7 @@ void main() {
Assets.images.flipper.left.keyName,
Assets.images.flipper.right.keyName,
Assets.images.boundary.outer.keyName,
Assets.images.boundary.outerBottom.keyName,
Assets.images.boundary.bottom.keyName,
Assets.images.slingshot.upper.keyName,
Assets.images.slingshot.lower.keyName,

@ -30,7 +30,7 @@ void main() {
rank: '1',
playerInitials: 'ABC',
score: 1500,
character: DashTheme().character,
character: DashTheme().leaderboardIcon,
);
test(

@ -121,7 +121,7 @@ void main() {
rank: '1',
playerInitials: 'ABC',
score: 10000,
character: DashTheme().character,
character: DashTheme().leaderboardIcon,
),
],
),

Loading…
Cancel
Save