fix: fixed merge conflicts on main

pull/97/head
RuiAlonso 4 years ago
commit a00783e9a3

@ -27,33 +27,30 @@ class LauncherRamp extends Component with HasGameRef<PinballGame> {
RampOpeningBallContactCallback<_LauncherRampOpening>(),
);
final launcherRampRotation =
-math.atan(18.6 / PinballGame.boardBounds.height);
final straightPath = Pathway.straight(
color: const Color.fromARGB(255, 34, 255, 0),
start: position + Vector2(-1.2, 10),
end: position + Vector2(-1.2, 117),
width: 5,
rotation: launcherRampRotation,
start: position + Vector2(-4.5, -10),
end: position + Vector2(-4.5, 117),
width: 4,
rotation: PinballGame.boardPerspectiveAngle,
)
..initialPosition = position
..layer = layer;
final curvedPath = Pathway.arc(
color: const Color.fromARGB(255, 251, 255, 0),
center: position + Vector2(-2.8, 87.2),
center: position + Vector2(-7, 87.2),
radius: 16.3,
angle: math.pi / 2,
width: 5,
width: 4,
rotation: 3 * math.pi / 2,
)..layer = layer;
final leftOpening = _LauncherRampOpening(rotation: math.pi / 2)
..initialPosition = position + Vector2(-11.8, 66.3)
..initialPosition = position + Vector2(-13.8, 66.7)
..layer = Layer.opening;
final rightOpening = _LauncherRampOpening(rotation: 0)
..initialPosition = position + Vector2(-4.9, 59.4)
..initialPosition = position + Vector2(-6.8, 59.4)
..layer = Layer.opening;
await addAll([
@ -81,9 +78,9 @@ class _LauncherRampOpening extends RampOpening {
final double _rotation;
// TODO(ruialonso): Avoid magic number 3, should be propotional to
// TODO(ruialonso): Avoid magic number 2.5, should be propotional to
// [JetpackRamp].
static final Vector2 _size = Vector2(3, .1);
static final Vector2 _size = Vector2(2.5, .1);
@override
Shape get shape => PolygonShape()

@ -21,9 +21,15 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
@override
Body createBody() {
final shape = PolygonShape()..setAsBoxXY(2, 0.75);
final shape = PolygonShape()
..setAsBox(
1.35,
0.5,
Vector2.zero(),
PinballGame.boardPerspectiveAngle,
);
final fixtureDef = FixtureDef(shape)..density = 5;
final fixtureDef = FixtureDef(shape)..density = 20;
final bodyDef = BodyDef()
..position = initialPosition
@ -36,7 +42,7 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
/// Set a constant downward velocity on the [Plunger].
void _pull() {
body.linearVelocity = Vector2(0, -3);
body.linearVelocity = Vector2(0, -7);
}
/// Set an upward velocity on the [Plunger].
@ -44,7 +50,7 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
/// The velocity's magnitude depends on how far the [Plunger] has been pulled
/// from its original [initialPosition].
void _release() {
final velocity = (initialPosition.y - body.position.y) * 9;
final velocity = (initialPosition.y - body.position.y) * 4;
body.linearVelocity = Vector2(0, velocity);
}
@ -121,12 +127,12 @@ class PlungerAnchorPrismaticJointDef extends PrismaticJointDef {
plunger.body,
anchor.body,
anchor.body.position,
Vector2(0, -1),
Vector2(18.6, PinballGame.boardBounds.height),
);
enableLimit = true;
lowerTranslation = double.negativeInfinity;
enableMotor = true;
motorSpeed = 50;
motorSpeed = 80;
maxMotorForce = motorSpeed;
collideConnected = true;
}

@ -1,5 +1,7 @@
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:math' as math;
import 'package:flame/extensions.dart';
import 'package:flame/input.dart';
import 'package:flame_bloc/flame_bloc.dart';
@ -24,6 +26,8 @@ class PinballGame extends Forge2DGame
width: boardSize.x,
height: -boardSize.y,
);
static final boardPerspectiveAngle =
-math.atan(18.6 / PinballGame.boardBounds.height);
@override
void onAttach() {
@ -60,13 +64,8 @@ class PinballGame extends Forge2DGame
}
Future<void> _addPlunger() async {
plunger = Plunger(compressionDistance: 2);
plunger.initialPosition = boardBounds.bottomRight.toVector2() +
Vector2(
-5,
10,
);
plunger = Plunger(compressionDistance: 29)
..initialPosition = boardBounds.center.toVector2() + Vector2(41.5, -49);
await add(plunger);
}

@ -91,7 +91,7 @@ class LeaderboardRepository {
try {
final querySnapshot = await _firebaseFirestore
.collection('leaderboard')
.orderBy('score')
.orderBy('score', descending: true)
.limit(10)
.get();
documents = querySnapshot.docs;
@ -130,7 +130,7 @@ class LeaderboardRepository {
try {
final querySnapshot = await _firebaseFirestore
.collection('leaderboard')
.orderBy('score')
.orderBy('score', descending: true)
.get();
// TODO(allisonryan0002): see if we can find a more performant solution.

@ -82,7 +82,7 @@ void main() {
when(() => firestore.collection('leaderboard'))
.thenAnswer((_) => collectionReference);
when(() => collectionReference.orderBy('score'))
when(() => collectionReference.orderBy('score', descending: true))
.thenAnswer((_) => query);
when(() => query.limit(10)).thenAnswer((_) => query);
when(query.get).thenAnswer((_) async => querySnapshot);
@ -173,7 +173,7 @@ void main() {
.thenAnswer((_) => collectionReference);
when(() => collectionReference.add(any()))
.thenAnswer((_) async => documentReference);
when(() => collectionReference.orderBy('score'))
when(() => collectionReference.orderBy('score', descending: true))
.thenAnswer((_) => query);
when(query.get).thenAnswer((_) async => querySnapshot);
when(() => querySnapshot.docs).thenReturn(queryDocumentSnapshots);
@ -203,7 +203,8 @@ void main() {
test(
'throws FetchPlayerRankingException when Exception occurs '
'when trying to retrieve information from firestore', () async {
when(() => collectionReference.orderBy('score')).thenThrow(Exception());
when(() => collectionReference.orderBy('score', descending: true))
.thenThrow(Exception());
expect(
() => leaderboardRepository.addLeaderboardEntry(leaderboardEntry),

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:ui';
import 'package:flame/components.dart';
@ -22,11 +23,14 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
}
/// The size of the [Ball]
final Vector2 size = Vector2.all(2);
final Vector2 size = Vector2.all(3);
/// The base [Color] used to tint this [Ball]
final Color baseColor;
double _boostTimer = 0;
static const _boostDuration = 2.0;
@override
Future<void> onLoad() async {
await super.onLoad();
@ -69,4 +73,26 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
void resume() {
body.setType(BodyType.dynamic);
}
@override
void update(double dt) {
super.update(dt);
if (_boostTimer > 0) {
_boostTimer -= dt;
final direction = body.linearVelocity.normalized();
final effect = FireEffect(
burstPower: _boostTimer,
direction: direction,
position: body.position,
);
unawaited(gameRef.add(effect));
}
}
/// Applies a boost on this [Ball]
void boost(Vector2 impulse) {
body.applyLinearImpulse(impulse);
_boostTimer = _boostDuration;
}
}

@ -1,3 +1,4 @@
export 'ball.dart';
export 'fire_effect.dart';
export 'initial_position.dart';
export 'layer.dart';

@ -0,0 +1,113 @@
import 'dart:math' as math;
import 'package:flame/extensions.dart';
import 'package:flame/particles.dart';
import 'package:flame_forge2d/flame_forge2d.dart' hide Particle;
import 'package:flutter/material.dart';
const _particleRadius = 0.25;
// TODO(erickzanardo): This component could just be a ParticleComponet,
/// unfortunately there is a Particle Component is not a PositionComponent,
/// which makes it hard to be used since we have camera transformations and on
// top of that, PositionComponent has a bug inside forge 2d games
///
/// https://github.com/flame-engine/flame/issues/1484
/// https://github.com/flame-engine/flame/issues/1484
/// {@template fire_effect}
/// A [BodyComponent] which creates a fire trail effect using the given
/// parameters
/// {@endtemplate}
class FireEffect extends BodyComponent {
/// {@macro fire_effect}
FireEffect({
required this.burstPower,
required this.position,
required this.direction,
});
/// A [double] value that will define how "strong" the burst of particles
/// will be
final double burstPower;
/// The position of the burst
final Vector2 position;
/// Which direction the burst will aim
final Vector2 direction;
late Particle _particle;
@override
Body createBody() {
final bodyDef = BodyDef()..position = position;
final fixtureDef = FixtureDef(CircleShape()..radius = 0)..isSensor = true;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
@override
Future<void> onLoad() async {
await super.onLoad();
final children = [
...List.generate(4, (index) {
return CircleParticle(
radius: _particleRadius,
paint: Paint()..color = Colors.yellow.darken((index + 1) / 4),
);
}),
...List.generate(4, (index) {
return CircleParticle(
radius: _particleRadius,
paint: Paint()..color = Colors.red.darken((index + 1) / 4),
);
}),
...List.generate(4, (index) {
return CircleParticle(
radius: _particleRadius,
paint: Paint()..color = Colors.orange.darken((index + 1) / 4),
);
}),
];
final rng = math.Random();
final spreadTween = Tween<double>(begin: -0.2, end: 0.2);
_particle = Particle.generate(
count: (rng.nextDouble() * (burstPower * 10)).toInt(),
generator: (_) {
final spread = Vector2(
spreadTween.transform(rng.nextDouble()),
spreadTween.transform(rng.nextDouble()),
);
final finalDirection = Vector2(direction.x, -direction.y) + spread;
final speed = finalDirection * (burstPower * 20);
return AcceleratedParticle(
lifespan: 5 / burstPower,
position: Vector2.zero(),
speed: speed,
child: children[rng.nextInt(children.length)],
);
},
);
}
@override
void update(double dt) {
super.update(dt);
_particle.update(dt);
if (_particle.shouldRemove) {
removeFromParent();
}
}
@override
void render(Canvas canvas) {
super.render(canvas);
_particle.render(canvas);
}
}

@ -1,11 +1,2 @@
import 'package:flame_forge2d/flame_forge2d.dart';
String buildSourceLink(String path) {
return 'https://github.com/VGVentures/pinball/tree/main/packages/pinball_components/sandbox/lib/stories/$path';
}
class BasicGame extends Forge2DGame {
BasicGame() {
images.prefix = '';
}
}
export 'games.dart';
export 'methods.dart';

@ -0,0 +1,74 @@
import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
class BasicGame extends Forge2DGame {
BasicGame() {
images.prefix = '';
}
}
abstract class LineGame extends BasicGame with PanDetector {
Vector2? _lineEnd;
@override
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
unawaited(add(_PreviewLine()));
}
@override
void onPanStart(DragStartInfo info) {
_lineEnd = info.eventPosition.game;
}
@override
void onPanUpdate(DragUpdateInfo info) {
_lineEnd = info.eventPosition.game;
}
@override
void onPanEnd(DragEndInfo info) {
if (_lineEnd != null) {
final line = _lineEnd! - Vector2.zero();
onLine(line);
_lineEnd = null;
}
}
void onLine(Vector2 line);
}
class _PreviewLine extends PositionComponent with HasGameRef<LineGame> {
static final _previewLinePaint = Paint()
..color = Colors.pink
..strokeWidth = 0.2
..style = PaintingStyle.stroke;
Vector2? lineEnd;
@override
void update(double dt) {
super.update(dt);
lineEnd = gameRef._lineEnd?.clone()?..multiply(Vector2(1, -1));
}
@override
void render(Canvas canvas) {
super.render(canvas);
if (lineEnd != null) {
canvas.drawLine(
Vector2.zero().toOffset(),
lineEnd!.toOffset(),
_previewLinePaint,
);
}
}
}

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

@ -6,6 +6,7 @@
// https://opensource.org/licenses/MIT.
import 'package:dashbook/dashbook.dart';
import 'package:flutter/material.dart';
import 'package:sandbox/stories/effects/effects.dart';
import 'package:sandbox/stories/stories.dart';
void main() {
@ -13,5 +14,6 @@ void main() {
addBallStories(dashbook);
addLayerStories(dashbook);
addEffectsStories(dashbook);
runApp(dashbook);
}

@ -2,17 +2,27 @@ 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.dart';
import 'package:sandbox/stories/ball/basic.dart';
void addBallStories(Dashbook dashbook) {
dashbook.storiesOf('Ball').add(
'Basic',
(context) => GameWidget(
game: BasicBallGame(
color: context.colorProperty('color', Colors.blue),
),
dashbook.storiesOf('Ball')
..add(
'Basic',
(context) => GameWidget(
game: BasicBallGame(
color: context.colorProperty('color', Colors.blue),
),
codeLink: buildSourceLink('ball/basic.dart'),
info: BasicBallGame.info,
);
),
codeLink: buildSourceLink('ball/basic.dart'),
info: BasicBallGame.info,
)
..add(
'Booster',
(context) => GameWidget(
game: BallBoosterExample(),
),
codeLink: buildSourceLink('ball/ball_booster.dart'),
info: BallBoosterExample.info,
);
}

@ -0,0 +1,16 @@
import 'package:flame/components.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BallBoosterExample extends LineGame {
static const info = '';
@override
void onLine(Vector2 line) {
final ball = Ball(baseColor: Colors.transparent);
add(ball);
ball.mounted.then((value) => ball.boost(line * -1 * 20));
}
}

@ -0,0 +1,13 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/effects/fire_effect.dart';
void addEffectsStories(Dashbook dashbook) {
dashbook.storiesOf('Effects').add(
'Fire Effect',
(context) => GameWidget(game: FireEffectExample()),
codeLink: buildSourceLink('effects/fire_effect.dart'),
info: FireEffectExample.info,
);
}

@ -0,0 +1,46 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class FireEffectExample extends LineGame {
static const info = 'Demonstrate the fire trail effect '
'drag a line to define the trail direction';
@override
void onLine(Vector2 line) {
add(_EffectEmitter(line));
}
}
class _EffectEmitter extends Component {
_EffectEmitter(this.line) {
_direction = line.normalized();
_force = line.length;
}
static const _timerLimit = 2.0;
var _timer = _timerLimit;
final Vector2 line;
late Vector2 _direction;
late double _force;
@override
void update(double dt) {
super.update(dt);
if (_timer > 0) {
add(
FireEffect(
burstPower: (_timer / _timerLimit) * _force,
position: Vector2.zero(),
direction: _direction,
),
);
_timer -= dt;
} else {
removeFromParent();
}
}
}

@ -1 +1,2 @@
export 'mocks.dart';
export 'test_game.dart';

@ -0,0 +1,5 @@
import 'dart:ui';
import 'package:mocktail/mocktail.dart';
class MockCanvas extends Mock implements Canvas {}

@ -86,7 +86,7 @@ void main() {
final fixture = ball.body.fixtures[0];
expect(fixture.shape.shapeType, equals(ShapeType.circle));
expect(fixture.shape.radius, equals(1));
expect(fixture.shape.radius, equals(1.5));
},
);
@ -158,5 +158,29 @@ void main() {
);
});
});
group('boost', () {
flameTester.test('applies an impulse to the ball', (game) async {
final ball = Ball(baseColor: Colors.blue);
await game.ensureAdd(ball);
expect(ball.body.linearVelocity, equals(Vector2.zero()));
ball.boost(Vector2.all(10));
expect(ball.body.linearVelocity.x, greaterThan(0));
expect(ball.body.linearVelocity.y, greaterThan(0));
});
flameTester.test('adds fire effect components to the game', (game) async {
final ball = Ball(baseColor: Colors.blue);
await game.ensureAdd(ball);
ball.boost(Vector2.all(10));
game.update(0);
await game.ready();
expect(game.children.whereType<FireEffect>().length, greaterThan(0));
});
});
});
}

@ -0,0 +1,55 @@
// 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:mocktail/mocktail.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new);
setUpAll(() {
registerFallbackValue(Offset.zero);
registerFallbackValue(Paint());
});
group('FireEffect', () {
flameTester.test('is removed once its particles are done', (game) async {
await game.ensureAdd(
FireEffect(
burstPower: 1,
position: Vector2.zero(),
direction: Vector2.all(2),
),
);
await game.ready();
expect(game.children.whereType<FireEffect>().length, equals(1));
game.update(5);
await game.ready();
expect(game.children.whereType<FireEffect>().length, equals(0));
});
flameTester.test('render circles on the canvas', (game) async {
final effect = FireEffect(
burstPower: 1,
position: Vector2.zero(),
direction: Vector2.all(2),
);
await game.ensureAdd(effect);
await game.ready();
final canvas = MockCanvas();
effect.render(canvas);
verify(() => canvas.drawCircle(any(), any(), any()))
.called(greaterThan(0));
});
});
}
Loading…
Cancel
Save