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