Merge branch 'main' into feat/launch-ramp-flapper

pull/312/head
Alejandro Santiago 3 years ago committed by GitHub
commit 39e3f5d556
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,8 +1 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
export 'view/app.dart'; export 'view/app.dart';

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
// ignore_for_file: public_member_api_docs // ignore_for_file: public_member_api_docs
import 'package:authentication_repository/authentication_repository.dart'; import 'package:authentication_repository/authentication_repository.dart';

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
// ignore_for_file: public_member_api_docs // ignore_for_file: public_member_api_docs
import 'dart:async'; import 'dart:async';

@ -5,7 +5,6 @@ import 'package:flame/components.dart';
import 'package:flame/game.dart'; import 'package:flame/game.dart';
import 'package:flame/input.dart'; import 'package:flame/input.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
@ -14,7 +13,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
import 'package:pinball_theme/pinball_theme.dart'; import 'package:pinball_theme/pinball_theme.dart';
class PinballGame extends Forge2DGame class PinballGame extends PinballForge2DGame
with with
FlameBloc, FlameBloc,
HasKeyboardHandlerComponents, HasKeyboardHandlerComponents,

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
// ignore_for_file: public_member_api_docs // ignore_for_file: public_member_api_docs
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:async'; import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart'; import 'package:authentication_repository/authentication_repository.dart';

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:async'; import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart'; import 'package:authentication_repository/authentication_repository.dart';

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:async'; import 'dart:async';
import 'package:authentication_repository/authentication_repository.dart'; import 'package:authentication_repository/authentication_repository.dart';

@ -1,18 +1,18 @@
import 'dart:async'; import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui';
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/ball/behaviors/ball_gravitating_behavior.dart';
import 'package:pinball_components/src/components/ball/behaviors/ball_scaling_behavior.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template ball} /// {@template ball}
/// A solid, [BodyType.dynamic] sphere that rolls and bounces around. /// A solid, [BodyType.dynamic] sphere that rolls and bounces around.
/// {@endtemplate} /// {@endtemplate}
class Ball<T extends Forge2DGame> extends BodyComponent<T> class Ball extends BodyComponent with Layered, InitialPosition, ZIndex {
with Layered, InitialPosition, ZIndex {
/// {@macro ball} /// {@macro ball}
Ball({ Ball({
required this.baseColor, required this.baseColor,
@ -20,6 +20,8 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
renderBody: false, renderBody: false,
children: [ children: [
_BallSpriteComponent()..tint(baseColor.withOpacity(0.5)), _BallSpriteComponent()..tint(baseColor.withOpacity(0.5)),
BallScalingBehavior(),
BallGravitatingBehavior(),
], ],
) { ) {
// TODO(ruimiguel): while developing Ball can be launched by clicking mouse, // TODO(ruimiguel): while developing Ball can be launched by clicking mouse,
@ -30,6 +32,15 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
layer = Layer.board; layer = Layer.board;
} }
/// Creates a [Ball] without any behaviors.
///
/// This can be used for testing [Ball]'s behaviors in isolation.
@visibleForTesting
Ball.test({required this.baseColor})
: super(
children: [_BallSpriteComponent()],
);
/// The size of the [Ball]. /// The size of the [Ball].
static final Vector2 size = Vector2.all(4.13); static final Vector2 size = Vector2.all(4.13);
@ -76,48 +87,6 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
body.linearVelocity = impulse; body.linearVelocity = impulse;
await add(_TurboChargeSpriteAnimationComponent()); await add(_TurboChargeSpriteAnimationComponent());
} }
@override
void update(double dt) {
super.update(dt);
_rescaleSize();
_setPositionalGravity();
}
void _rescaleSize() {
final boardHeight = BoardDimensions.bounds.height;
const maxShrinkValue = BoardDimensions.perspectiveShrinkFactor;
final standardizedYPosition = body.position.y + (boardHeight / 2);
final scaleFactor = maxShrinkValue +
((standardizedYPosition / boardHeight) * (1 - maxShrinkValue));
body.fixtures.first.shape.radius = (size.x / 2) * scaleFactor;
// TODO(alestiago): Revisit and see if there's a better way to do this.
final spriteComponent = firstChild<_BallSpriteComponent>();
spriteComponent?.scale = Vector2.all(scaleFactor);
}
void _setPositionalGravity() {
final defaultGravity = gameRef.world.gravity.y;
final maxXDeviationFromCenter = BoardDimensions.bounds.width / 2;
const maxXGravityPercentage =
(1 - BoardDimensions.perspectiveShrinkFactor) / 2;
final xDeviationFromCenter = body.position.x;
final positionalXForce = ((xDeviationFromCenter / maxXDeviationFromCenter) *
maxXGravityPercentage) *
defaultGravity;
final positionalYForce = math.sqrt(
math.pow(defaultGravity, 2) - math.pow(positionalXForce, 2),
);
body.gravityOverride = Vector2(positionalXForce, positionalYForce);
}
} }
class _BallSpriteComponent extends SpriteComponent with HasGameRef { class _BallSpriteComponent extends SpriteComponent with HasGameRef {

@ -0,0 +1,35 @@
import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Scales the ball's gravity according to its position on the board.
class BallGravitatingBehavior extends Component
with ParentIsA<Ball>, HasGameRef<Forge2DGame> {
@override
void update(double dt) {
super.update(dt);
final defaultGravity = gameRef.world.gravity.y;
final maxXDeviationFromCenter = BoardDimensions.bounds.width / 2;
const maxXGravityPercentage =
(1 - BoardDimensions.perspectiveShrinkFactor) / 2;
final xDeviationFromCenter = parent.body.position.x;
final positionalXForce = ((xDeviationFromCenter / maxXDeviationFromCenter) *
maxXGravityPercentage) *
defaultGravity;
final positionalYForce = math.sqrt(
math.pow(defaultGravity, 2) - math.pow(positionalXForce, 2),
);
final gravityOverride = parent.body.gravityOverride;
if (gravityOverride != null) {
gravityOverride.setValues(positionalXForce, positionalYForce);
} else {
parent.body.gravityOverride = Vector2(positionalXForce, positionalYForce);
}
}
}

@ -0,0 +1,24 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Scales the ball's body and sprite according to its position on the board.
class BallScalingBehavior extends Component with ParentIsA<Ball> {
@override
void update(double dt) {
super.update(dt);
final boardHeight = BoardDimensions.bounds.height;
const maxShrinkValue = BoardDimensions.perspectiveShrinkFactor;
final standardizedYPosition = parent.body.position.y + (boardHeight / 2);
final scaleFactor = maxShrinkValue +
((standardizedYPosition / boardHeight) * (1 - maxShrinkValue));
parent.body.fixtures.first.shape.radius = (Ball.size.x / 2) * scaleFactor;
parent.firstChild<SpriteComponent>()!.scale.setValues(
scaleFactor,
scaleFactor,
);
}
}

@ -0,0 +1,2 @@
export 'ball_gravitating_behavior.dart';
export 'ball_scaling_behavior.dart';

@ -2,7 +2,7 @@ export 'android_animatronic.dart';
export 'android_bumper/android_bumper.dart'; export 'android_bumper/android_bumper.dart';
export 'android_spaceship/android_spaceship.dart'; export 'android_spaceship/android_spaceship.dart';
export 'backboard/backboard.dart'; export 'backboard/backboard.dart';
export 'ball.dart'; export 'ball/ball.dart';
export 'baseboard.dart'; export 'baseboard.dart';
export 'board_background_sprite_component.dart'; export 'board_background_sprite_component.dart';
export 'board_dimensions.dart'; export 'board_dimensions.dart';

@ -5,7 +5,7 @@ import 'package:flame_forge2d/flame_forge2d.dart';
/// ///
/// Note: If the [initialPosition] is set after the [BodyComponent] has been /// Note: If the [initialPosition] is set after the [BodyComponent] has been
/// loaded it will have no effect; defaulting to [Vector2.zero]. /// loaded it will have no effect; defaulting to [Vector2.zero].
mixin InitialPosition<T extends Forge2DGame> on BodyComponent<T> { mixin InitialPosition on BodyComponent {
final Vector2 _initialPosition = Vector2.zero(); final Vector2 _initialPosition = Vector2.zero();
set initialPosition(Vector2 value) { set initialPosition(Vector2 value) {

@ -9,7 +9,7 @@ import 'package:flutter/material.dart';
/// ignoring others. This compatibility depends on bit masking operation /// ignoring others. This compatibility depends on bit masking operation
/// between layers. For more information read: https://en.wikipedia.org/wiki/Mask_(computing). /// between layers. For more information read: https://en.wikipedia.org/wiki/Mask_(computing).
/// {@endtemplate} /// {@endtemplate}
mixin Layered<T extends Forge2DGame> on BodyComponent<T> { mixin Layered on BodyComponent {
Layer _layer = Layer.all; Layer _layer = Layer.all;
/// {@macro layered} /// {@macro layered}

@ -1,9 +1,3 @@
// Copyright (c) 2022, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'package:dashbook/dashbook.dart'; import 'package:dashbook/dashbook.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sandbox/stories/stories.dart'; import 'package:sandbox/stories/stories.dart';

@ -6,18 +6,29 @@ import 'package:flame_test/flame_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.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 'package:pinball_components/src/components/ball/behaviors/behaviors.dart';
import '../../helpers/helpers.dart'; import '../../../helpers/helpers.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new); final flameTester = FlameTester(TestGame.new);
group('Ball', () { group('Ball', () {
const baseColor = Color(0xFFFFFFFF);
test(
'can be instantiated',
() {
expect(Ball(baseColor: baseColor), isA<Ball>());
expect(Ball.test(baseColor: baseColor), isA<Ball>());
},
);
flameTester.test( flameTester.test(
'loads correctly', 'loads correctly',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ready(); await game.ready();
await game.ensureAdd(ball); await game.ensureAdd(ball);
@ -25,11 +36,31 @@ void main() {
}, },
); );
group('adds', () {
flameTester.test('a BallScalingBehavior', (game) async {
final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball);
expect(
ball.descendants().whereType<BallScalingBehavior>().length,
equals(1),
);
});
flameTester.test('a BallGravitatingBehavior', (game) async {
final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball);
expect(
ball.descendants().whereType<BallGravitatingBehavior>().length,
equals(1),
);
});
});
group('body', () { group('body', () {
flameTester.test( flameTester.test(
'is dynamic', 'is dynamic',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
expect(ball.body.bodyType, equals(BodyType.dynamic)); expect(ball.body.bodyType, equals(BodyType.dynamic));
@ -38,7 +69,7 @@ void main() {
group('can be moved', () { group('can be moved', () {
flameTester.test('by its weight', (game) async { flameTester.test('by its weight', (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
game.update(1); game.update(1);
@ -46,7 +77,7 @@ void main() {
}); });
flameTester.test('by applying velocity', (game) async { flameTester.test('by applying velocity', (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
ball.body.gravityScale = Vector2.zero(); ball.body.gravityScale = Vector2.zero();
@ -61,7 +92,7 @@ void main() {
flameTester.test( flameTester.test(
'exists', 'exists',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
expect(ball.body.fixtures[0], isA<Fixture>()); expect(ball.body.fixtures[0], isA<Fixture>());
@ -71,7 +102,7 @@ void main() {
flameTester.test( flameTester.test(
'is dense', 'is dense',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
final fixture = ball.body.fixtures[0]; final fixture = ball.body.fixtures[0];
@ -82,7 +113,7 @@ void main() {
flameTester.test( flameTester.test(
'shape is circular', 'shape is circular',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
final fixture = ball.body.fixtures[0]; final fixture = ball.body.fixtures[0];
@ -94,7 +125,7 @@ void main() {
flameTester.test( flameTester.test(
'has Layer.all as default filter maskBits', 'has Layer.all as default filter maskBits',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ready(); await game.ready();
await game.ensureAdd(ball); await game.ensureAdd(ball);
await game.ready(); await game.ready();
@ -108,7 +139,7 @@ void main() {
group('stop', () { group('stop', () {
group("can't be moved", () { group("can't be moved", () {
flameTester.test('by its weight', (game) async { flameTester.test('by its weight', (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
ball.stop(); ball.stop();
@ -116,19 +147,6 @@ void main() {
expect(ball.body.position, equals(ball.initialPosition)); expect(ball.body.position, equals(ball.initialPosition));
}); });
}); });
// TODO(allisonryan0002): delete or retest this if/when solution is added
// to prevent forces on a ball while stopped.
// flameTester.test('by applying velocity', (game) async {
// final ball = Ball(baseColor: Colors.blue);
// await game.ensureAdd(ball);
// ball.stop();
// ball.body.linearVelocity.setValues(10, 10);
// game.update(1);
// expect(ball.body.position, equals(ball.initialPosition));
// });
}); });
group('resume', () { group('resume', () {
@ -136,7 +154,7 @@ void main() {
flameTester.test( flameTester.test(
'by its weight when previously stopped', 'by its weight when previously stopped',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
ball.stop(); ball.stop();
ball.resume(); ball.resume();
@ -149,7 +167,7 @@ void main() {
flameTester.test( flameTester.test(
'by applying velocity when previously stopped', 'by applying velocity when previously stopped',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
ball.stop(); ball.stop();
ball.resume(); ball.resume();
@ -165,7 +183,7 @@ void main() {
group('boost', () { group('boost', () {
flameTester.test('applies an impulse to the ball', (game) async { flameTester.test('applies an impulse to the ball', (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
expect(ball.body.linearVelocity, equals(Vector2.zero())); expect(ball.body.linearVelocity, equals(Vector2.zero()));
@ -176,7 +194,7 @@ void main() {
}); });
flameTester.test('adds TurboChargeSpriteAnimation', (game) async { flameTester.test('adds TurboChargeSpriteAnimation', (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
await ball.boost(Vector2.all(10)); await ball.boost(Vector2.all(10));
@ -190,7 +208,7 @@ void main() {
flameTester.test('removes TurboChargeSpriteAnimation after it finishes', flameTester.test('removes TurboChargeSpriteAnimation after it finishes',
(game) async { (game) async {
final ball = Ball(baseColor: Colors.blue); final ball = Ball(baseColor: baseColor);
await game.ensureAdd(ball); await game.ensureAdd(ball);
await ball.boost(Vector2.all(10)); await ball.boost(Vector2.all(10));

@ -0,0 +1,63 @@
// ignore_for_file: cascade_invocations
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/ball/behaviors/behaviors.dart';
import '../../../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final asset = Assets.images.ball.ball.keyName;
final flameTester = FlameTester(() => TestGame([asset]));
group('BallGravitatingBehavior', () {
const baseColor = Color(0xFFFFFFFF);
test('can be instantiated', () {
expect(
BallGravitatingBehavior(),
isA<BallGravitatingBehavior>(),
);
});
flameTester.test('can be loaded', (game) async {
final ball = Ball.test(baseColor: baseColor);
final behavior = BallGravitatingBehavior();
await ball.add(behavior);
await game.ensureAdd(ball);
expect(
ball.firstChild<BallGravitatingBehavior>(),
equals(behavior),
);
});
flameTester.test(
"overrides the body's horizontal gravity symmetrically",
(game) async {
final ball1 = Ball.test(baseColor: baseColor)
..initialPosition = Vector2(10, 0);
await ball1.add(BallGravitatingBehavior());
final ball2 = Ball.test(baseColor: baseColor)
..initialPosition = Vector2(-10, 0);
await ball2.add(BallGravitatingBehavior());
await game.ensureAddAll([ball1, ball2]);
game.update(1);
expect(
ball1.body.gravityOverride!.x,
equals(-ball2.body.gravityOverride!.x),
);
expect(
ball1.body.gravityOverride!.y,
equals(ball2.body.gravityOverride!.y),
);
},
);
});
}

@ -0,0 +1,85 @@
// ignore_for_file: cascade_invocations
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_components/src/components/ball/behaviors/behaviors.dart';
import '../../../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final asset = Assets.images.ball.ball.keyName;
final flameTester = FlameTester(() => TestGame([asset]));
group('BallScalingBehavior', () {
const baseColor = Color(0xFFFFFFFF);
test('can be instantiated', () {
expect(
BallScalingBehavior(),
isA<BallScalingBehavior>(),
);
});
flameTester.test('can be loaded', (game) async {
final ball = Ball.test(baseColor: baseColor);
final behavior = BallScalingBehavior();
await ball.add(behavior);
await game.ensureAdd(ball);
expect(
ball.firstChild<BallScalingBehavior>(),
equals(behavior),
);
});
flameTester.test('scales the shape radius', (game) async {
final ball1 = Ball.test(baseColor: baseColor)
..initialPosition = Vector2(0, 10);
await ball1.add(BallScalingBehavior());
final ball2 = Ball.test(baseColor: baseColor)
..initialPosition = Vector2(0, -10);
await ball2.add(BallScalingBehavior());
await game.ensureAddAll([ball1, ball2]);
game.update(1);
final shape1 = ball1.body.fixtures.first.shape;
final shape2 = ball2.body.fixtures.first.shape;
expect(
shape1.radius,
greaterThan(shape2.radius),
);
});
flameTester.test(
'scales the sprite',
(game) async {
final ball1 = Ball.test(baseColor: baseColor)
..initialPosition = Vector2(0, 10);
await ball1.add(BallScalingBehavior());
final ball2 = Ball.test(baseColor: baseColor)
..initialPosition = Vector2(0, -10);
await ball2.add(BallScalingBehavior());
await game.ensureAddAll([ball1, ball2]);
game.update(1);
final sprite1 = ball1.firstChild<SpriteComponent>()!;
final sprite2 = ball2.firstChild<SpriteComponent>()!;
expect(
sprite1.scale.x,
greaterThan(sprite2.scale.x),
);
expect(
sprite1.scale.y,
greaterThan(sprite2.scale.y),
);
},
);
});
}

@ -4,5 +4,6 @@ export 'src/component_controller.dart';
export 'src/contact_behavior.dart'; export 'src/contact_behavior.dart';
export 'src/keyboard_input_controller.dart'; export 'src/keyboard_input_controller.dart';
export 'src/parent_is_a.dart'; export 'src/parent_is_a.dart';
export 'src/pinball_forge2d_game.dart';
export 'src/sprite_animation.dart'; export 'src/sprite_animation.dart';
export 'src/z_canvas_component.dart'; export 'src/z_canvas_component.dart';

@ -0,0 +1,44 @@
import 'dart:math';
import 'package:flame/game.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_forge2d/world_contact_listener.dart';
// NOTE(wolfen): This should be removed when https://github.com/flame-engine/flame/pull/1597 is solved.
/// {@template pinball_forge2d_game}
/// A [Game] that uses the Forge2D physics engine.
/// {@endtemplate}
class PinballForge2DGame extends FlameGame implements Forge2DGame {
/// {@macro pinball_forge2d_game}
PinballForge2DGame({
required Vector2 gravity,
}) : world = World(gravity),
super(camera: Camera()) {
camera.zoom = Forge2DGame.defaultZoom;
world.setContactListener(WorldContactListener());
}
@override
final World world;
@override
void update(double dt) {
super.update(dt);
world.stepDt(min(dt, 1 / 60));
}
@override
Vector2 screenToFlameWorld(Vector2 position) {
throw UnimplementedError();
}
@override
Vector2 screenToWorld(Vector2 position) {
throw UnimplementedError();
}
@override
Vector2 worldToScreen(Vector2 position) {
throw UnimplementedError();
}
}

@ -0,0 +1,51 @@
// ignore_for_file: cascade_invocations
import 'package:flame/extensions.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_flame/pinball_flame.dart';
void main() {
final flameTester = FlameTester(
() => PinballForge2DGame(gravity: Vector2.zero()),
);
group('PinballForge2DGame', () {
test('can instantiate', () {
expect(
() => PinballForge2DGame(gravity: Vector2.zero()),
returnsNormally,
);
});
flameTester.test(
'screenToFlameWorld throws UnimpelementedError',
(game) async {
expect(
() => game.screenToFlameWorld(Vector2.zero()),
throwsUnimplementedError,
);
},
);
flameTester.test(
'screenToWorld throws UnimpelementedError',
(game) async {
expect(
() => game.screenToWorld(Vector2.zero()),
throwsUnimplementedError,
);
},
);
flameTester.test(
'worldToScreen throws UnimpelementedError',
(game) async {
expect(
() => game.worldToScreen(Vector2.zero()),
throwsUnimplementedError,
);
},
);
});
}

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'package:authentication_repository/authentication_repository.dart'; import 'package:authentication_repository/authentication_repository.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart';

@ -2,7 +2,6 @@
import 'package:bloc_test/bloc_test.dart'; import 'package:bloc_test/bloc_test.dart';
import 'package:flame/extensions.dart'; import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.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:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
@ -15,7 +14,7 @@ import '../../helpers/helpers.dart';
// TODO(allisonryan0002): remove once // TODO(allisonryan0002): remove once
// https://github.com/flame-engine/flame/pull/1520 is merged // https://github.com/flame-engine/flame/pull/1520 is merged
class _WrappedBallController extends BallController { class _WrappedBallController extends BallController {
_WrappedBallController(Ball<Forge2DGame> ball, this._gameRef) : super(ball); _WrappedBallController(Ball ball, this._gameRef) : super(ball);
final PinballGame _gameRef; final PinballGame _gameRef;

@ -1,9 +1,3 @@
//
// Copyright (c) 2021, Very Good Ventures
// Use of this source code is governed by an MIT-style
// https://opensource.org/licenses/MIT.
// https://verygood.ventures
// license that can be found in the LICENSE file or at
export 'builders.dart'; export 'builders.dart';
export 'fakes.dart'; export 'fakes.dart';
export 'forge2d.dart'; export 'forge2d.dart';

@ -1,10 +1,3 @@
// Copyright (c) 2021, Very Good Ventures
// https://verygood.ventures
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'package:bloc_test/bloc_test.dart'; import 'package:bloc_test/bloc_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';

Loading…
Cancel
Save