mirror of https://github.com/flutter/pinball.git
refactor: moved boost logic to `BallTurboChargingBehavior` (#323)
* feat(pinball_components): defined BallTurboChargingBehavior * feat: updated boosting logic * docs: improved BallTurboChargingBehavior * docs(pinball_components): changed verb * test: removed empty group * test: included instantiation and loading testspull/328/head
parent
b0f6709828
commit
44566bcbf0
@ -0,0 +1,81 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template ball_turbo_charging_behavior}
|
||||||
|
/// Puts the [Ball] in flames and [_impulse]s it.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class BallTurboChargingBehavior extends TimerComponent with ParentIsA<Ball> {
|
||||||
|
/// {@macro ball_turbo_charging_behavior}
|
||||||
|
BallTurboChargingBehavior({
|
||||||
|
required Vector2 impulse,
|
||||||
|
}) : _impulse = impulse,
|
||||||
|
super(period: 5, removeOnFinish: true);
|
||||||
|
|
||||||
|
final Vector2 _impulse;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
|
||||||
|
parent.body.linearVelocity = _impulse;
|
||||||
|
await parent.add(_TurboChargeSpriteAnimationComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onRemove() {
|
||||||
|
parent
|
||||||
|
.firstChild<_TurboChargeSpriteAnimationComponent>()!
|
||||||
|
.removeFromParent();
|
||||||
|
super.onRemove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TurboChargeSpriteAnimationComponent extends SpriteAnimationComponent
|
||||||
|
with HasGameRef, ZIndex, ParentIsA<Ball> {
|
||||||
|
_TurboChargeSpriteAnimationComponent()
|
||||||
|
: super(
|
||||||
|
anchor: const Anchor(0.53, 0.72),
|
||||||
|
) {
|
||||||
|
zIndex = ZIndexes.turboChargeFlame;
|
||||||
|
}
|
||||||
|
|
||||||
|
late final Vector2 _textureSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void update(double dt) {
|
||||||
|
super.update(dt);
|
||||||
|
|
||||||
|
final direction = -parent.body.linearVelocity.normalized();
|
||||||
|
angle = math.atan2(direction.x, -direction.y);
|
||||||
|
size = (_textureSize / 45) * parent.body.fixtures.first.shape.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
|
||||||
|
final spriteSheet = await gameRef.images.load(
|
||||||
|
Assets.images.ball.flameEffect.keyName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const amountPerRow = 8;
|
||||||
|
const amountPerColumn = 4;
|
||||||
|
_textureSize = Vector2(
|
||||||
|
spriteSheet.width / amountPerRow,
|
||||||
|
spriteSheet.height / amountPerColumn,
|
||||||
|
);
|
||||||
|
|
||||||
|
animation = SpriteAnimation.fromFrameData(
|
||||||
|
spriteSheet,
|
||||||
|
SpriteAnimationData.sequenced(
|
||||||
|
amount: amountPerRow * amountPerColumn,
|
||||||
|
amountPerRow: amountPerRow,
|
||||||
|
stepTime: 1 / 24,
|
||||||
|
textureSize: _textureSize,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export 'ball_gravitating_behavior.dart';
|
export 'ball_gravitating_behavior.dart';
|
||||||
export 'ball_scaling_behavior.dart';
|
export 'ball_scaling_behavior.dart';
|
||||||
|
export 'ball_turbo_charging_behavior.dart';
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group(
|
||||||
|
'BallTurboChargingBehavior',
|
||||||
|
() {
|
||||||
|
final assets = [Assets.images.ball.ball.keyName];
|
||||||
|
final flameTester = FlameTester(() => TestGame(assets));
|
||||||
|
const baseColor = Color(0xFFFFFFFF);
|
||||||
|
|
||||||
|
test('can be instantiated', () {
|
||||||
|
expect(
|
||||||
|
BallTurboChargingBehavior(impulse: Vector2.zero()),
|
||||||
|
isA<BallTurboChargingBehavior>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('can be loaded', (game) async {
|
||||||
|
final ball = Ball.test(baseColor: baseColor);
|
||||||
|
final behavior = BallTurboChargingBehavior(impulse: Vector2.zero());
|
||||||
|
await ball.add(behavior);
|
||||||
|
await game.ensureAdd(ball);
|
||||||
|
expect(
|
||||||
|
ball.firstChild<BallTurboChargingBehavior>(),
|
||||||
|
equals(behavior),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test(
|
||||||
|
'impulses the ball velocity when loaded',
|
||||||
|
(game) async {
|
||||||
|
final ball = Ball.test(baseColor: baseColor);
|
||||||
|
await game.ensureAdd(ball);
|
||||||
|
final impulse = Vector2.all(1);
|
||||||
|
final behavior = BallTurboChargingBehavior(impulse: impulse);
|
||||||
|
await ball.ensureAdd(behavior);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
ball.body.linearVelocity.x,
|
||||||
|
equals(impulse.x),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ball.body.linearVelocity.y,
|
||||||
|
equals(impulse.y),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
flameTester.test('adds sprite', (game) async {
|
||||||
|
final ball = Ball(baseColor: baseColor);
|
||||||
|
await game.ensureAdd(ball);
|
||||||
|
|
||||||
|
await ball.ensureAdd(
|
||||||
|
BallTurboChargingBehavior(impulse: Vector2.zero()),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
ball.children.whereType<SpriteAnimationComponent>().single,
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
flameTester.test('removes sprite after it finishes', (game) async {
|
||||||
|
final ball = Ball(baseColor: baseColor);
|
||||||
|
await game.ensureAdd(ball);
|
||||||
|
|
||||||
|
final behavior = BallTurboChargingBehavior(impulse: Vector2.zero());
|
||||||
|
await ball.ensureAdd(behavior);
|
||||||
|
|
||||||
|
final turboChargeSpriteAnimation =
|
||||||
|
ball.children.whereType<SpriteAnimationComponent>().single;
|
||||||
|
|
||||||
|
expect(ball.contains(turboChargeSpriteAnimation), isTrue);
|
||||||
|
|
||||||
|
game.update(behavior.timer.limit);
|
||||||
|
game.update(0.1);
|
||||||
|
|
||||||
|
expect(ball.contains(turboChargeSpriteAnimation), isFalse);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in new issue