mirror of https://github.com/flutter/pinball.git
parent
72a377b1b0
commit
aabc4f21af
@ -1,78 +0,0 @@
|
|||||||
// ignore_for_file: avoid_renaming_method_parameters
|
|
||||||
|
|
||||||
import 'package:flame/components.dart';
|
|
||||||
import 'package:pinball/game/game.dart';
|
|
||||||
import 'package:pinball_components/pinball_components.dart';
|
|
||||||
import 'package:pinball_flame/pinball_flame.dart';
|
|
||||||
|
|
||||||
/// {@template flutter_forest}
|
|
||||||
/// Area positioned at the top right of the [Board] where the [Ball]
|
|
||||||
/// can bounce off [DashNestBumper]s.
|
|
||||||
///
|
|
||||||
/// When all [DashNestBumper]s are hit at least once, the [GameBonus.dashNest]
|
|
||||||
/// is awarded, and the [DashNestBumper.main] releases a new [Ball].
|
|
||||||
/// {@endtemplate}
|
|
||||||
class FlutterForest extends Component
|
|
||||||
with Controls<_FlutterForestController>, HasGameRef<PinballGame> {
|
|
||||||
/// {@macro flutter_forest}
|
|
||||||
FlutterForest()
|
|
||||||
: super(
|
|
||||||
children: [
|
|
||||||
Signpost(
|
|
||||||
children: [
|
|
||||||
ScoringBehavior(points: 20),
|
|
||||||
],
|
|
||||||
)..initialPosition = Vector2(8.35, -58.3),
|
|
||||||
DashNestBumper.main(
|
|
||||||
children: [
|
|
||||||
ScoringBehavior(points: 20),
|
|
||||||
],
|
|
||||||
)..initialPosition = Vector2(18.55, -59.35),
|
|
||||||
DashNestBumper.a(
|
|
||||||
children: [
|
|
||||||
ScoringBehavior(points: 20),
|
|
||||||
],
|
|
||||||
)..initialPosition = Vector2(8.95, -51.95),
|
|
||||||
DashNestBumper.b(
|
|
||||||
children: [
|
|
||||||
ScoringBehavior(points: 20),
|
|
||||||
],
|
|
||||||
)..initialPosition = Vector2(23.3, -46.75),
|
|
||||||
DashAnimatronic()..position = Vector2(20, -66),
|
|
||||||
],
|
|
||||||
) {
|
|
||||||
controller = _FlutterForestController(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FlutterForestController extends ComponentController<FlutterForest>
|
|
||||||
with HasGameRef<PinballGame> {
|
|
||||||
_FlutterForestController(FlutterForest flutterForest) : super(flutterForest);
|
|
||||||
|
|
||||||
final _activatedBumpers = <DashNestBumper>{};
|
|
||||||
|
|
||||||
void activateBumper(DashNestBumper dashNestBumper) {
|
|
||||||
if (!_activatedBumpers.add(dashNestBumper)) return;
|
|
||||||
|
|
||||||
dashNestBumper.activate();
|
|
||||||
|
|
||||||
final activatedBonus = _activatedBumpers.length == 3;
|
|
||||||
if (activatedBonus) {
|
|
||||||
_addBonusBall();
|
|
||||||
|
|
||||||
gameRef.read<GameBloc>().add(const BonusActivated(GameBonus.dashNest));
|
|
||||||
_activatedBumpers
|
|
||||||
..forEach((bumper) => bumper.deactivate())
|
|
||||||
..clear();
|
|
||||||
|
|
||||||
component.firstChild<DashAnimatronic>()?.playing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _addBonusBall() async {
|
|
||||||
await gameRef.add(
|
|
||||||
ControlledBall.bonus(characterTheme: gameRef.characterTheme)
|
|
||||||
..initialPosition = Vector2(17.2, -52.7),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1 @@
|
|||||||
|
export 'flutter_forest_bonus_behavior.dart';
|
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// When all [DashNestBumper]s are hit at least once, the [GameBonus.dashNest]
|
||||||
|
/// is awarded, and the [DashNestBumper.main] releases a new [Ball].
|
||||||
|
class FlutterForestBonusBehavior extends Component
|
||||||
|
with ParentIsA<FlutterForest>, HasGameRef<PinballGame> {
|
||||||
|
@override
|
||||||
|
void onMount() {
|
||||||
|
super.onMount();
|
||||||
|
// TODO(alestiago): Refactor subscription management once the following is
|
||||||
|
// merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
parent.bloc.stream.listen(_onNewState);
|
||||||
|
|
||||||
|
final bumpers = parent.children.whereType<DashNestBumper>();
|
||||||
|
for (final bumper in bumpers) {
|
||||||
|
bumper.bloc.stream.listen((state) {
|
||||||
|
if (state == DashNestBumperState.active) {
|
||||||
|
parent.bloc.onBumperActivated(bumper);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onNewState(FlutterForestState state) {
|
||||||
|
if (state.hasBonus) {
|
||||||
|
gameRef.read<GameBloc>().add(const BonusActivated(GameBonus.dashNest));
|
||||||
|
|
||||||
|
gameRef.add(
|
||||||
|
ControlledBall.bonus(theme: gameRef.theme)
|
||||||
|
..initialPosition = Vector2(17.2, -52.7),
|
||||||
|
);
|
||||||
|
parent.firstChild<DashAnimatronic>()?.playing = true;
|
||||||
|
for (final bumper in state.activatedBumpers) {
|
||||||
|
bumper.bloc.onReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.bloc.onBonusApplied();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
part 'flutter_forest_state.dart';
|
||||||
|
|
||||||
|
class FlutterForestCubit extends Cubit<FlutterForestState> {
|
||||||
|
FlutterForestCubit() : super(FlutterForestState.initial());
|
||||||
|
|
||||||
|
void onBumperActivated(DashNestBumper dashNestBumper) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
activatedBumpers: state.activatedBumpers.union({dashNestBumper}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBonusApplied() {
|
||||||
|
emit(
|
||||||
|
state.copyWith(activatedBumpers: const {}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
part of 'flutter_forest_cubit.dart';
|
||||||
|
|
||||||
|
class FlutterForestState extends Equatable {
|
||||||
|
const FlutterForestState({
|
||||||
|
required this.activatedBumpers,
|
||||||
|
});
|
||||||
|
|
||||||
|
const FlutterForestState.initial() : this(activatedBumpers: const {});
|
||||||
|
|
||||||
|
final Set<DashNestBumper> activatedBumpers;
|
||||||
|
|
||||||
|
bool get hasBonus => activatedBumpers.length == 3;
|
||||||
|
|
||||||
|
FlutterForestState copyWith({
|
||||||
|
Set<DashNestBumper>? activatedBumpers,
|
||||||
|
}) {
|
||||||
|
return FlutterForestState(
|
||||||
|
activatedBumpers: activatedBumpers ?? this.activatedBumpers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [activatedBumpers];
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
// ignore_for_file: avoid_renaming_method_parameters
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball/game/components/flutter_forest/behaviors/behaviors.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
export 'cubit/flutter_forest_cubit.dart';
|
||||||
|
|
||||||
|
/// {@template flutter_forest}
|
||||||
|
/// Area positioned at the top right of the [Board] where the [Ball]
|
||||||
|
/// can bounce off [DashNestBumper]s.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class FlutterForest extends Component {
|
||||||
|
/// {@macro flutter_forest}
|
||||||
|
FlutterForest()
|
||||||
|
: bloc = FlutterForestCubit(),
|
||||||
|
super(
|
||||||
|
children: [
|
||||||
|
Signpost(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(8.35, -58.3),
|
||||||
|
DashNestBumper.main(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(18.55, -59.35),
|
||||||
|
DashNestBumper.a(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(8.95, -51.95),
|
||||||
|
DashNestBumper.b(
|
||||||
|
children: [
|
||||||
|
ScoringBehavior(points: 20),
|
||||||
|
],
|
||||||
|
)..initialPosition = Vector2(23.3, -46.75),
|
||||||
|
DashAnimatronic()..position = Vector2(20, -66),
|
||||||
|
FlutterForestBonusBehavior(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/// {@macro flutter_forest}
|
||||||
|
@visibleForTesting
|
||||||
|
FlutterForest.test({
|
||||||
|
required this.bloc,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(alestiago): Consider refactoring once the following is merged:
|
||||||
|
// https://github.com/flame-engine/flame/pull/1538
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
final FlutterForestCubit bloc;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onRemove() {
|
||||||
|
bloc.close();
|
||||||
|
super.onRemove();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
export 'dash_nest_bumper_contact_behavior.dart';
|
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
// TODO(alestiago): Evaluate if there is any useful documentation that could
|
||||||
|
// be added to this class.
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
class DashBumperBallContactBehavior extends ContactBehavior<DashNestBumper> {
|
||||||
|
@override
|
||||||
|
void beginContact(Object other, Contact contact) {
|
||||||
|
super.beginContact(other, contact);
|
||||||
|
if (other is! Ball) return;
|
||||||
|
parent.bloc.onBallContacted();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
|
||||||
|
part 'dash_nest_bumper_state.dart';
|
||||||
|
|
||||||
|
// TODO(alestiago): Evaluate if there is any useful documentation that could
|
||||||
|
// be added to this class.
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
class DashNestBumperCubit extends Cubit<DashNestBumperState> {
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
DashNestBumperCubit() : super(DashNestBumperState.inactive);
|
||||||
|
|
||||||
|
/// Event added when the bumper contacts with a ball.
|
||||||
|
void onBallContacted() {
|
||||||
|
emit(DashNestBumperState.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event added when the bumper should return to its initial configuration.
|
||||||
|
void onReset() {
|
||||||
|
emit(DashNestBumperState.inactive);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
part of 'dash_nest_bumper_cubit.dart';
|
||||||
|
|
||||||
|
/// Indicates the [DashNestBumperCubit]'s current state.
|
||||||
|
enum DashNestBumperState {
|
||||||
|
/// A lit up bumper.
|
||||||
|
active,
|
||||||
|
|
||||||
|
/// A dimmed bumper.
|
||||||
|
inactive,
|
||||||
|
}
|
Loading…
Reference in new issue