|
|
@ -1,9 +1,7 @@
|
|
|
|
// ignore_for_file: avoid_renaming_method_parameters
|
|
|
|
// ignore_for_file: avoid_renaming_method_parameters
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:flame/components.dart';
|
|
|
|
import 'package:flame/components.dart';
|
|
|
|
import 'package:flame_bloc/flame_bloc.dart';
|
|
|
|
|
|
|
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
|
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
import 'package:pinball/game/game.dart';
|
|
|
|
import 'package:pinball/game/game.dart';
|
|
|
|
import 'package:pinball_components/pinball_components.dart';
|
|
|
|
import 'package:pinball_components/pinball_components.dart';
|
|
|
|
import 'package:pinball_flame/pinball_flame.dart';
|
|
|
|
import 'package:pinball_flame/pinball_flame.dart';
|
|
|
@ -15,9 +13,8 @@ import 'package:pinball_flame/pinball_flame.dart';
|
|
|
|
/// When all [DashNestBumper]s are hit at least once, the [GameBonus.dashNest]
|
|
|
|
/// When all [DashNestBumper]s are hit at least once, the [GameBonus.dashNest]
|
|
|
|
/// is awarded, and the [BigDashNestBumper] releases a new [Ball].
|
|
|
|
/// is awarded, and the [BigDashNestBumper] releases a new [Ball].
|
|
|
|
/// {@endtemplate}
|
|
|
|
/// {@endtemplate}
|
|
|
|
// TODO(alestiago): Make a [Blueprint] once [Blueprint] inherits from
|
|
|
|
class FlutterForest extends Component
|
|
|
|
// [Component].
|
|
|
|
with Controls<_FlutterForestController>, HasGameRef<PinballGame> {
|
|
|
|
class FlutterForest extends Component with Controls<_FlutterForestController> {
|
|
|
|
|
|
|
|
/// {@macro flutter_forest}
|
|
|
|
/// {@macro flutter_forest}
|
|
|
|
FlutterForest() {
|
|
|
|
FlutterForest() {
|
|
|
|
controller = _FlutterForestController(this);
|
|
|
|
controller = _FlutterForestController(this);
|
|
|
@ -26,17 +23,16 @@ class FlutterForest extends Component with Controls<_FlutterForestController> {
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
Future<void> onLoad() async {
|
|
|
|
Future<void> onLoad() async {
|
|
|
|
await super.onLoad();
|
|
|
|
await super.onLoad();
|
|
|
|
|
|
|
|
gameRef.addContactCallback(_DashNestBumperBallContactCallback());
|
|
|
|
|
|
|
|
|
|
|
|
final signPost = FlutterSignPost()..initialPosition = Vector2(8.35, -58.3);
|
|
|
|
final signPost = FlutterSignPost()..initialPosition = Vector2(8.35, -58.3);
|
|
|
|
|
|
|
|
|
|
|
|
final bigNest = _ControlledBigDashNestBumper(
|
|
|
|
final bigNest = _BigDashNestBumper()
|
|
|
|
id: 'big_nest_bumper',
|
|
|
|
..initialPosition = Vector2(18.55, -59.35);
|
|
|
|
)..initialPosition = Vector2(18.55, -59.35);
|
|
|
|
final smallLeftNest = _SmallDashNestBumper.a()
|
|
|
|
final smallLeftNest = _ControlledSmallDashNestBumper.a(
|
|
|
|
..initialPosition = Vector2(8.95, -51.95);
|
|
|
|
id: 'small_nest_bumper_a',
|
|
|
|
final smallRightNest = _SmallDashNestBumper.b()
|
|
|
|
)..initialPosition = Vector2(8.95, -51.95);
|
|
|
|
..initialPosition = Vector2(23.3, -46.75);
|
|
|
|
final smallRightNest = _ControlledSmallDashNestBumper.b(
|
|
|
|
|
|
|
|
id: 'small_nest_bumper_b',
|
|
|
|
|
|
|
|
)..initialPosition = Vector2(23.3, -46.75);
|
|
|
|
|
|
|
|
final dashAnimatronic = DashAnimatronic()..position = Vector2(20, -66);
|
|
|
|
final dashAnimatronic = DashAnimatronic()..position = Vector2(20, -66);
|
|
|
|
|
|
|
|
|
|
|
|
await addAll([
|
|
|
|
await addAll([
|
|
|
@ -50,31 +46,31 @@ class FlutterForest extends Component with Controls<_FlutterForestController> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _FlutterForestController extends ComponentController<FlutterForest>
|
|
|
|
class _FlutterForestController extends ComponentController<FlutterForest>
|
|
|
|
with BlocComponent<GameBloc, GameState>, HasGameRef<PinballGame> {
|
|
|
|
with HasGameRef<PinballGame> {
|
|
|
|
_FlutterForestController(FlutterForest flutterForest) : super(flutterForest);
|
|
|
|
_FlutterForestController(FlutterForest flutterForest) : super(flutterForest);
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
final _activatedBumpers = <DashNestBumper>{};
|
|
|
|
Future<void> onLoad() async {
|
|
|
|
|
|
|
|
await super.onLoad();
|
|
|
|
|
|
|
|
gameRef.addContactCallback(_ControlledDashNestBumperBallContactCallback());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
void activateBumper(DashNestBumper dashNestBumper) {
|
|
|
|
bool listenWhen(GameState? previousState, GameState newState) {
|
|
|
|
if (!_activatedBumpers.add(dashNestBumper)) return;
|
|
|
|
return (previousState?.bonusHistory.length ?? 0) <
|
|
|
|
|
|
|
|
newState.bonusHistory.length &&
|
|
|
|
|
|
|
|
newState.bonusHistory.last == GameBonus.dashNest;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
dashNestBumper.activate();
|
|
|
|
void onNewState(GameState state) {
|
|
|
|
|
|
|
|
super.onNewState(state);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
component.firstChild<DashAnimatronic>()?.playing = true;
|
|
|
|
final activatedBonus = _activatedBumpers.length == 3;
|
|
|
|
|
|
|
|
if (activatedBonus) {
|
|
|
|
_addBonusBall();
|
|
|
|
_addBonusBall();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gameRef.read<GameBloc>().add(const BonusActivated(GameBonus.dashNest));
|
|
|
|
|
|
|
|
_activatedBumpers
|
|
|
|
|
|
|
|
..forEach((bumper) => bumper.deactivate())
|
|
|
|
|
|
|
|
..clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
component.firstChild<DashAnimatronic>()?.playing = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _addBonusBall() async {
|
|
|
|
Future<void> _addBonusBall() async {
|
|
|
|
|
|
|
|
// TODO(alestiago): Remove hardcoded duration.
|
|
|
|
await Future<void>.delayed(const Duration(milliseconds: 700));
|
|
|
|
await Future<void>.delayed(const Duration(milliseconds: 700));
|
|
|
|
await gameRef.add(
|
|
|
|
await gameRef.add(
|
|
|
|
ControlledBall.bonus(theme: gameRef.theme)
|
|
|
|
ControlledBall.bonus(theme: gameRef.theme)
|
|
|
@ -83,83 +79,29 @@ class _FlutterForestController extends ComponentController<FlutterForest>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _ControlledBigDashNestBumper extends BigDashNestBumper
|
|
|
|
// TODO(alestiago): Revisit ScorePoints logic once the FlameForge2D
|
|
|
|
with Controls<DashNestBumperController>, ScorePoints {
|
|
|
|
// ContactCallback process is enhanced.
|
|
|
|
_ControlledBigDashNestBumper({required String id}) : super() {
|
|
|
|
class _BigDashNestBumper extends BigDashNestBumper with ScorePoints {
|
|
|
|
controller = DashNestBumperController(this, id: id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
int get points => 20;
|
|
|
|
int get points => 20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _ControlledSmallDashNestBumper extends SmallDashNestBumper
|
|
|
|
class _SmallDashNestBumper extends SmallDashNestBumper with ScorePoints {
|
|
|
|
with Controls<DashNestBumperController>, ScorePoints {
|
|
|
|
_SmallDashNestBumper.a() : super.a();
|
|
|
|
_ControlledSmallDashNestBumper.a({required String id}) : super.a() {
|
|
|
|
|
|
|
|
controller = DashNestBumperController(this, id: id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_ControlledSmallDashNestBumper.b({required String id}) : super.b() {
|
|
|
|
_SmallDashNestBumper.b() : super.b();
|
|
|
|
controller = DashNestBumperController(this, id: id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
int get points => 10;
|
|
|
|
int get points => 20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// {@template dash_nest_bumper_controller}
|
|
|
|
class _DashNestBumperBallContactCallback
|
|
|
|
/// Controls a [DashNestBumper].
|
|
|
|
extends ContactCallback<DashNestBumper, Ball> {
|
|
|
|
/// {@endtemplate}
|
|
|
|
|
|
|
|
@visibleForTesting
|
|
|
|
|
|
|
|
class DashNestBumperController extends ComponentController<DashNestBumper>
|
|
|
|
|
|
|
|
with BlocComponent<GameBloc, GameState>, HasGameRef<PinballGame> {
|
|
|
|
|
|
|
|
/// {@macro dash_nest_bumper_controller}
|
|
|
|
|
|
|
|
DashNestBumperController(
|
|
|
|
|
|
|
|
DashNestBumper dashNestBumper, {
|
|
|
|
|
|
|
|
required this.id,
|
|
|
|
|
|
|
|
}) : super(dashNestBumper);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Unique identifier for the controlled [DashNestBumper].
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Used to identify [DashNestBumper]s in [GameState.activatedDashNests].
|
|
|
|
|
|
|
|
final String id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
bool listenWhen(GameState? previousState, GameState newState) {
|
|
|
|
void begin(DashNestBumper dashNestBumper, _, __) {
|
|
|
|
final wasActive = previousState?.activatedDashNests.contains(id) ?? false;
|
|
|
|
final parent = dashNestBumper.parent;
|
|
|
|
final isActive = newState.activatedDashNests.contains(id);
|
|
|
|
if (parent is FlutterForest) {
|
|
|
|
|
|
|
|
parent.controller.activateBumper(dashNestBumper);
|
|
|
|
return wasActive != isActive;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
|
|
void onNewState(GameState state) {
|
|
|
|
|
|
|
|
super.onNewState(state);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (state.activatedDashNests.contains(id)) {
|
|
|
|
|
|
|
|
component.activate();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
component.deactivate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Registers when a [DashNestBumper] is hit by a [Ball].
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Triggered by [_ControlledDashNestBumperBallContactCallback].
|
|
|
|
|
|
|
|
void hit() {
|
|
|
|
|
|
|
|
gameRef.read<GameBloc>().add(DashNestActivated(id));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Listens when a [Ball] bounces bounces against a [DashNestBumper].
|
|
|
|
|
|
|
|
class _ControlledDashNestBumperBallContactCallback
|
|
|
|
|
|
|
|
extends ContactCallback<Controls<DashNestBumperController>, Ball> {
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
|
|
void begin(
|
|
|
|
|
|
|
|
Controls<DashNestBumperController> controlledDashNestBumper,
|
|
|
|
|
|
|
|
Ball _,
|
|
|
|
|
|
|
|
Contact __,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
controlledDashNestBumper.controller.hit();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|