Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 2.2 MiB |
@ -1,45 +0,0 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_bloc/flame_bloc.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:pinball_flame/pinball_flame.dart';
|
|
||||||
|
|
||||||
/// {@template score_effect_controller}
|
|
||||||
/// A [ComponentController] responsible for adding [ScoreText]s
|
|
||||||
/// on the game screen when the user earns points.
|
|
||||||
/// {@endtemplate}
|
|
||||||
class ScoreEffectController extends ComponentController<PinballGame>
|
|
||||||
with BlocComponent<GameBloc, GameState> {
|
|
||||||
/// {@macro score_effect_controller}
|
|
||||||
ScoreEffectController(PinballGame component) : super(component);
|
|
||||||
|
|
||||||
int _lastScore = 0;
|
|
||||||
final _random = Random();
|
|
||||||
|
|
||||||
double _noise() {
|
|
||||||
return _random.nextDouble() * 5 * (_random.nextBool() ? -1 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool listenWhen(GameState? previousState, GameState newState) {
|
|
||||||
return previousState?.score != newState.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onNewState(GameState state) {
|
|
||||||
final newScore = state.score - _lastScore;
|
|
||||||
_lastScore = state.score;
|
|
||||||
|
|
||||||
component.add(
|
|
||||||
ScoreText(
|
|
||||||
text: newScore.toString(),
|
|
||||||
position: Vector2(
|
|
||||||
_noise(),
|
|
||||||
_noise() + (BoardDimensions.bounds.topCenter.dy + 10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1 @@
|
|||||||
|
export 'assets.gen.dart';
|
@ -1 +0,0 @@
|
|||||||
export 'view/landing_page.dart';
|
|
@ -1 +1,2 @@
|
|||||||
export 'bloc/start_game_bloc.dart';
|
export 'bloc/start_game_bloc.dart';
|
||||||
|
export 'widgets/widgets.dart';
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export 'how_to_play_dialog.dart';
|
@ -0,0 +1,15 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
abstract class AppColors {
|
||||||
|
static const Color white = Color(0xFFFFFFFF);
|
||||||
|
|
||||||
|
static const Color darkBlue = Color(0xFF0C32A4);
|
||||||
|
|
||||||
|
static const Color orange = Color(0xFFFFEE02);
|
||||||
|
|
||||||
|
static const Color blue = Color(0xFF4B94F6);
|
||||||
|
|
||||||
|
static const Color transparent = Color(0x00000000);
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:pinball/theme/theme.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
const _fontPackage = 'pinball_components';
|
||||||
|
const _primaryFontFamily = PinballFonts.pixeloidSans;
|
||||||
|
|
||||||
|
abstract class AppTextStyle {
|
||||||
|
static const headline1 = TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
package: _fontPackage,
|
||||||
|
fontFamily: _primaryFontFamily,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const headline2 = TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
package: _fontPackage,
|
||||||
|
fontFamily: _primaryFontFamily,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const headline3 = TextStyle(
|
||||||
|
color: AppColors.white,
|
||||||
|
fontSize: 20,
|
||||||
|
package: _fontPackage,
|
||||||
|
fontFamily: _primaryFontFamily,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const subtitle1 = TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontFamily: _primaryFontFamily,
|
||||||
|
package: _fontPackage,
|
||||||
|
);
|
||||||
|
}
|
@ -1,2 +1,4 @@
|
|||||||
|
export 'app_colors.dart';
|
||||||
|
export 'app_text_style.dart';
|
||||||
export 'cubit/theme_cubit.dart';
|
export 'cubit/theme_cubit.dart';
|
||||||
export 'view/view.dart';
|
export 'view/view.dart';
|
||||||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 290 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 6.5 KiB |
@ -0,0 +1,2 @@
|
|||||||
|
export 'assets.gen.dart';
|
||||||
|
export 'pinball_fonts.dart';
|
@ -1,16 +1,14 @@
|
|||||||
import 'package:pinball_components/gen/fonts.gen.dart';
|
import 'package:pinball_components/gen/fonts.gen.dart';
|
||||||
|
|
||||||
String _prefixFont(String font) {
|
const String _fontPath = 'packages/pinball_components/';
|
||||||
return 'packages/pinball_components/$font';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Class with the fonts available on the pinball game
|
/// Class with the fonts available on the pinball game
|
||||||
class PinballFonts {
|
class PinballFonts {
|
||||||
PinballFonts._();
|
PinballFonts._();
|
||||||
|
|
||||||
/// Mono variation of the Pixeloid font
|
/// Mono variation of the Pixeloid font
|
||||||
static final String pixeloidMono = _prefixFont(FontFamily.pixeloidMono);
|
static const String pixeloidMono = '$_fontPath/${FontFamily.pixeloidMono}';
|
||||||
|
|
||||||
/// Sans variation of the Pixeloid font
|
/// Sans variation of the Pixeloid font
|
||||||
static final String pixeloidSans = _prefixFont(FontFamily.pixeloidMono);
|
static const String pixeloidSans = '$_fontPath/${FontFamily.pixeloidSans}';
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
library pinball_components;
|
library pinball_components;
|
||||||
|
|
||||||
export 'gen/assets.gen.dart';
|
export 'gen/gen.dart';
|
||||||
export 'gen/pinball_fonts.dart';
|
|
||||||
export 'src/pinball_components.dart';
|
export 'src/pinball_components.dart';
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
|
|
||||||
/// {@template flutter_sign_post}
|
|
||||||
/// A sign, found in the Flutter Forest.
|
|
||||||
/// {@endtemplate}
|
|
||||||
class FlutterSignPost extends BodyComponent with InitialPosition {
|
|
||||||
/// {@macro flutter_sign_post}
|
|
||||||
FlutterSignPost()
|
|
||||||
: super(
|
|
||||||
children: [_FlutterSignPostSpriteComponent()],
|
|
||||||
) {
|
|
||||||
renderBody = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Body createBody() {
|
|
||||||
final shape = CircleShape()..radius = 0.25;
|
|
||||||
final fixtureDef = FixtureDef(shape);
|
|
||||||
final bodyDef = BodyDef(
|
|
||||||
position: initialPosition,
|
|
||||||
);
|
|
||||||
|
|
||||||
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FlutterSignPostSpriteComponent extends SpriteComponent with HasGameRef {
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
await super.onLoad();
|
|
||||||
|
|
||||||
final sprite = await gameRef.loadSprite(
|
|
||||||
Assets.images.flutterSignPost.keyName,
|
|
||||||
);
|
|
||||||
this.sprite = sprite;
|
|
||||||
size = sprite.originalSize / 10;
|
|
||||||
anchor = Anchor.bottomCenter;
|
|
||||||
position = Vector2(0.65, 0.45);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,116 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// {@template render_priority}
|
||||||
|
/// Priorities for the component rendering order in the pinball game.
|
||||||
|
/// {@endtemplate}
|
||||||
|
// TODO(allisonryan0002): find alternative to section comments.
|
||||||
|
abstract class RenderPriority {
|
||||||
|
static const _base = 0;
|
||||||
|
static const _above = 1;
|
||||||
|
static const _below = -1;
|
||||||
|
|
||||||
|
// Ball
|
||||||
|
|
||||||
|
/// Render priority for the [Ball] while it's on the board.
|
||||||
|
static const int ballOnBoard = _base;
|
||||||
|
|
||||||
|
/// Render priority for the [Ball] while it's on the [SpaceshipRamp].
|
||||||
|
static const int ballOnSpaceshipRamp =
|
||||||
|
_above + spaceshipRampBackgroundRailing;
|
||||||
|
|
||||||
|
/// Render priority for the [Ball] while it's on the [Spaceship].
|
||||||
|
static const int ballOnSpaceship = _above + spaceshipSaucer;
|
||||||
|
|
||||||
|
/// Render priority for the [Ball] while it's on the [SpaceshipRail].
|
||||||
|
static const int ballOnSpaceshipRail = _below + spaceshipSaucer;
|
||||||
|
|
||||||
|
/// Render priority for the [Ball] while it's on the [LaunchRamp].
|
||||||
|
static const int ballOnLaunchRamp = _above + launchRamp;
|
||||||
|
|
||||||
|
// Background
|
||||||
|
|
||||||
|
// TODO(allisonryan0002): fix this magic priority. Could bump all priorities
|
||||||
|
// so there are no negatives.
|
||||||
|
static const int background = 3 * _below + _base;
|
||||||
|
|
||||||
|
// Boundaries
|
||||||
|
|
||||||
|
static const int bottomBoundary = _above + dinoBottomWall;
|
||||||
|
|
||||||
|
static const int outerBoudary = _above + background;
|
||||||
|
|
||||||
|
// Bottom Group
|
||||||
|
|
||||||
|
static const int bottomGroup = _above + ballOnBoard;
|
||||||
|
|
||||||
|
// Launcher
|
||||||
|
|
||||||
|
static const int launchRamp = _above + outerBoudary;
|
||||||
|
|
||||||
|
static const int launchRampForegroundRailing = _above + ballOnLaunchRamp;
|
||||||
|
|
||||||
|
static const int plunger = _above + launchRamp;
|
||||||
|
|
||||||
|
static const int rocket = _above + bottomBoundary;
|
||||||
|
|
||||||
|
// Dino Land
|
||||||
|
|
||||||
|
static const int dinoTopWall = _above + ballOnBoard;
|
||||||
|
|
||||||
|
static const int dino = _above + dinoTopWall;
|
||||||
|
|
||||||
|
static const int dinoBottomWall = _above + dino;
|
||||||
|
|
||||||
|
static const int slingshot = _above + ballOnBoard;
|
||||||
|
|
||||||
|
// Flutter Forest
|
||||||
|
|
||||||
|
static const int signpost = _above + launchRampForegroundRailing;
|
||||||
|
|
||||||
|
static const int dashBumper = _above + ballOnBoard;
|
||||||
|
|
||||||
|
static const int dashAnimatronic = _above + launchRampForegroundRailing;
|
||||||
|
|
||||||
|
// Sparky Fire Zone
|
||||||
|
|
||||||
|
static const int computerBase = _below + ballOnBoard;
|
||||||
|
|
||||||
|
static const int computerTop = _above + ballOnBoard;
|
||||||
|
|
||||||
|
static const int sparkyAnimatronic = _above + spaceshipRampForegroundRailing;
|
||||||
|
|
||||||
|
static const int sparkyBumper = _above + ballOnBoard;
|
||||||
|
|
||||||
|
static const int turboChargeFlame = _above + ballOnBoard;
|
||||||
|
|
||||||
|
// Android Spaceship
|
||||||
|
|
||||||
|
static const int spaceshipRail = _above + bottomGroup;
|
||||||
|
|
||||||
|
static const int spaceshipRailForeground = _above + spaceshipRail;
|
||||||
|
|
||||||
|
static const int spaceshipSaucer = _above + spaceshipRail;
|
||||||
|
|
||||||
|
static const int spaceshipSaucerWall = _above + spaceshipSaucer;
|
||||||
|
|
||||||
|
static const int androidHead = _above + spaceshipSaucer;
|
||||||
|
|
||||||
|
static const int spaceshipRamp = _above + ballOnBoard;
|
||||||
|
|
||||||
|
static const int spaceshipRampBackgroundRailing = _above + spaceshipRamp;
|
||||||
|
|
||||||
|
static const int spaceshipRampArrow = _above + spaceshipRamp;
|
||||||
|
|
||||||
|
static const int spaceshipRampForegroundRailing =
|
||||||
|
_above + ballOnSpaceshipRamp;
|
||||||
|
|
||||||
|
static const int spaceshipRampBoardOpening = _below + ballOnBoard;
|
||||||
|
|
||||||
|
static const int alienBumper = _above + ballOnBoard;
|
||||||
|
|
||||||
|
// Score Text
|
||||||
|
|
||||||
|
static const int scoreText = _above + spaceshipRampForegroundRailing;
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// Represents the [Signpost]'s current [Sprite] state.
|
||||||
|
@visibleForTesting
|
||||||
|
enum SignpostSpriteState {
|
||||||
|
/// Signpost with no active dashes.
|
||||||
|
inactive,
|
||||||
|
|
||||||
|
/// Signpost with a single sign of active dashes.
|
||||||
|
active1,
|
||||||
|
|
||||||
|
/// Signpost with two signs of active dashes.
|
||||||
|
active2,
|
||||||
|
|
||||||
|
/// Signpost with all signs of active dashes.
|
||||||
|
active3,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on SignpostSpriteState {
|
||||||
|
String get path {
|
||||||
|
switch (this) {
|
||||||
|
case SignpostSpriteState.inactive:
|
||||||
|
return Assets.images.signpost.inactive.keyName;
|
||||||
|
case SignpostSpriteState.active1:
|
||||||
|
return Assets.images.signpost.active1.keyName;
|
||||||
|
case SignpostSpriteState.active2:
|
||||||
|
return Assets.images.signpost.active2.keyName;
|
||||||
|
case SignpostSpriteState.active3:
|
||||||
|
return Assets.images.signpost.active3.keyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SignpostSpriteState get next {
|
||||||
|
return SignpostSpriteState
|
||||||
|
.values[(index + 1) % SignpostSpriteState.values.length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template signpost}
|
||||||
|
/// A sign, found in the Flutter Forest.
|
||||||
|
///
|
||||||
|
/// Lights up a new sign whenever all three [DashNestBumper]s are hit.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class Signpost extends BodyComponent with InitialPosition {
|
||||||
|
/// {@macro signpost}
|
||||||
|
Signpost()
|
||||||
|
: super(
|
||||||
|
priority: RenderPriority.signpost,
|
||||||
|
children: [_SignpostSpriteComponent()],
|
||||||
|
) {
|
||||||
|
renderBody = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forwards the sprite to the next [SignpostSpriteState].
|
||||||
|
///
|
||||||
|
/// If the current state is the last one it cycles back to the initial state.
|
||||||
|
void progress() => firstChild<_SignpostSpriteComponent>()!.progress();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Body createBody() {
|
||||||
|
final shape = CircleShape()..radius = 0.25;
|
||||||
|
final fixtureDef = FixtureDef(shape);
|
||||||
|
final bodyDef = BodyDef(
|
||||||
|
position: initialPosition,
|
||||||
|
);
|
||||||
|
|
||||||
|
return world.createBody(bodyDef)..createFixture(fixtureDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SignpostSpriteComponent extends SpriteGroupComponent<SignpostSpriteState>
|
||||||
|
with HasGameRef {
|
||||||
|
_SignpostSpriteComponent()
|
||||||
|
: super(
|
||||||
|
anchor: Anchor.bottomCenter,
|
||||||
|
position: Vector2(0.65, 0.45),
|
||||||
|
);
|
||||||
|
|
||||||
|
void progress() => current = current?.next;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
|
||||||
|
final sprites = <SignpostSpriteState, Sprite>{};
|
||||||
|
this.sprites = sprites;
|
||||||
|
for (final spriteState in SignpostSpriteState.values) {
|
||||||
|
sprites[spriteState] = Sprite(
|
||||||
|
gameRef.images.fromCache(spriteState.path),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
current = SignpostSpriteState.inactive;
|
||||||
|
size = sprites[current]!.originalSize / 10;
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +0,0 @@
|
|||||||
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 FlutterSignPostGame extends BasicBallGame with Traceable {
|
|
||||||
static const info = '''
|
|
||||||
Shows how a FlutterSignPost is rendered.
|
|
||||||
|
|
||||||
- Activate the "trace" parameter to overlay the body.
|
|
||||||
''';
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> onLoad() async {
|
|
||||||
await super.onLoad();
|
|
||||||
camera.followVector2(Vector2.zero());
|
|
||||||
await add(FlutterSignPost()..priority = 1);
|
|
||||||
await traceAllBodies();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
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 = '''
|
||||||
|
Shows how a Signpost is rendered.
|
||||||
|
|
||||||
|
- Activate the "trace" parameter to overlay the body.
|
||||||
|
- Tap to progress the sprite.
|
||||||
|
''';
|
||||||
|
|
||||||
|
@override
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTap() {
|
||||||
|
super.onTap();
|
||||||
|
firstChild<Signpost>()!.progress();
|
||||||
|
}
|
||||||
|
}
|