mirror of https://github.com/flutter/pinball.git
parent
75feeaae26
commit
221d055a1e
@ -1,3 +1,4 @@
|
|||||||
export 'android_spaceship_bonus_behavior.dart';
|
export 'android_spaceship_bonus_behavior.dart';
|
||||||
export 'ramp_bonus_behavior.dart';
|
export 'ramp_bonus_behavior.dart';
|
||||||
|
export 'ramp_progress_behavior.dart';
|
||||||
export 'ramp_shot_behavior.dart';
|
export 'ramp_shot_behavior.dart';
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_bloc/flame_bloc.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template ramp_progress_behavior}
|
||||||
|
/// Increases the score when a [Ball] is shot into the [SpaceshipRamp].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class RampProgressBehavior extends Component
|
||||||
|
with ParentIsA<SpaceshipRamp>, FlameBlocReader<GameBloc, GameState> {
|
||||||
|
/// {@macro ramp_shot_behavior}
|
||||||
|
RampProgressBehavior() : super();
|
||||||
|
|
||||||
|
/// Creates a [RampProgressBehavior].
|
||||||
|
///
|
||||||
|
/// This can be used for testing [RampProgressBehavior] in isolation.
|
||||||
|
@visibleForTesting
|
||||||
|
RampProgressBehavior.test({
|
||||||
|
required this.subscription,
|
||||||
|
}) : super();
|
||||||
|
|
||||||
|
/// Subscription to [SpaceshipRampState] at [SpaceshipRamp].
|
||||||
|
@visibleForTesting
|
||||||
|
StreamSubscription? subscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onMount() {
|
||||||
|
super.onMount();
|
||||||
|
|
||||||
|
final spaceshipRamp = parent.children.whereType<SpaceshipRamp>().first;
|
||||||
|
|
||||||
|
var previousState = const SpaceshipRampState.initial();
|
||||||
|
|
||||||
|
subscription = subscription ??
|
||||||
|
parent.bloc.stream.listen((state) {
|
||||||
|
final listenWhen =
|
||||||
|
previousState.hits != state.hits && state.hits != 0;
|
||||||
|
if (listenWhen) {
|
||||||
|
var fullArrowLit = spaceshipRamp.bloc.isFullyProgressed();
|
||||||
|
var isMaxMultiplier = bloc.state.multiplier == 6;
|
||||||
|
final canProgress =
|
||||||
|
!isMaxMultiplier || (isMaxMultiplier && !fullArrowLit);
|
||||||
|
|
||||||
|
if (canProgress) {
|
||||||
|
spaceshipRamp.bloc.onProgressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
fullArrowLit = spaceshipRamp.bloc.isFullyProgressed();
|
||||||
|
isMaxMultiplier = bloc.state.multiplier == 6;
|
||||||
|
|
||||||
|
if (fullArrowLit && !isMaxMultiplier) {
|
||||||
|
spaceshipRamp.bloc.onAnimate();
|
||||||
|
}
|
||||||
|
|
||||||
|
previousState = state;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onRemove() {
|
||||||
|
subscription?.cancel();
|
||||||
|
super.onRemove();
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
|
export 'ramp_arrow_blinking_behavior.dart';
|
||||||
export 'ramp_ball_ascending_contact_behavior.dart';
|
export 'ramp_ball_ascending_contact_behavior.dart';
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:pinball_flame/pinball_flame.dart';
|
||||||
|
|
||||||
|
/// {@template ramp_arrow_blinking_behavior}
|
||||||
|
/// Makes a [SpaceshipRampArrowSpriteComponent] blink between [ArrowLightState.values].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class RampArrowBlinkingBehavior extends TimerComponent
|
||||||
|
with ParentIsA<SpaceshipRamp> {
|
||||||
|
/// {@macro ramp_arrow_blinking_behavior}
|
||||||
|
RampArrowBlinkingBehavior() : super(period: 0.05);
|
||||||
|
|
||||||
|
final _maxBlinks = 15;
|
||||||
|
|
||||||
|
int _blinksCounter = 0;
|
||||||
|
|
||||||
|
bool _isAnimating = false;
|
||||||
|
|
||||||
|
void _onNewState(SpaceshipRampState state) {
|
||||||
|
final animationEnabled =
|
||||||
|
state.animationState == ArrowAnimationState.blinking;
|
||||||
|
final canBlink = _blinksCounter < _maxBlinks;
|
||||||
|
|
||||||
|
if (animationEnabled && canBlink) {
|
||||||
|
_start();
|
||||||
|
} else {
|
||||||
|
_stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _start() {
|
||||||
|
if (!_isAnimating) {
|
||||||
|
_isAnimating = true;
|
||||||
|
timer
|
||||||
|
..reset()
|
||||||
|
..start();
|
||||||
|
_animate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _animate() {
|
||||||
|
parent.bloc.onBlink();
|
||||||
|
_blinksCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _stop() {
|
||||||
|
if (_isAnimating) {
|
||||||
|
_isAnimating = false;
|
||||||
|
timer.stop();
|
||||||
|
_blinksCounter = 0;
|
||||||
|
parent.bloc.onStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
parent.bloc.stream.listen(_onNewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTick() {
|
||||||
|
super.onTick();
|
||||||
|
if (!_isAnimating) {
|
||||||
|
timer.stop();
|
||||||
|
} else {
|
||||||
|
if (_blinksCounter < _maxBlinks) {
|
||||||
|
_animate();
|
||||||
|
timer
|
||||||
|
..reset()
|
||||||
|
..start();
|
||||||
|
} else {
|
||||||
|
timer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,64 @@
|
|||||||
|
// ignore_for_file: comment_references
|
||||||
|
|
||||||
part of 'spaceship_ramp_cubit.dart';
|
part of 'spaceship_ramp_cubit.dart';
|
||||||
|
|
||||||
class SpaceshipRampState extends Equatable {
|
class SpaceshipRampState extends Equatable {
|
||||||
const SpaceshipRampState({
|
const SpaceshipRampState({
|
||||||
required this.hits,
|
required this.hits,
|
||||||
|
required this.lightState,
|
||||||
|
required this.animationState,
|
||||||
}) : assert(hits >= 0, "Hits can't be negative");
|
}) : assert(hits >= 0, "Hits can't be negative");
|
||||||
|
|
||||||
const SpaceshipRampState.initial() : this(hits: 0);
|
const SpaceshipRampState.initial()
|
||||||
|
: this(
|
||||||
|
hits: 0,
|
||||||
|
lightState: ArrowLightState.inactive,
|
||||||
|
animationState: ArrowAnimationState.idle,
|
||||||
|
);
|
||||||
|
|
||||||
final int hits;
|
final int hits;
|
||||||
|
final ArrowLightState lightState;
|
||||||
|
final ArrowAnimationState animationState;
|
||||||
|
|
||||||
SpaceshipRampState copyWith({
|
SpaceshipRampState copyWith({
|
||||||
int? hits,
|
int? hits,
|
||||||
|
ArrowLightState? lightState,
|
||||||
|
ArrowAnimationState? animationState,
|
||||||
}) {
|
}) {
|
||||||
return SpaceshipRampState(
|
return SpaceshipRampState(
|
||||||
hits: hits ?? this.hits,
|
hits: hits ?? this.hits,
|
||||||
|
lightState: lightState ?? this.lightState,
|
||||||
|
animationState: animationState ?? this.animationState,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [hits];
|
List<Object?> get props => [hits, lightState, animationState];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates the state of the arrow on the [SpaceshipRamp].
|
||||||
|
enum ArrowLightState {
|
||||||
|
/// Arrow with no dashes lit up.
|
||||||
|
inactive,
|
||||||
|
|
||||||
|
/// Arrow with 1 light lit up.
|
||||||
|
active1,
|
||||||
|
|
||||||
|
/// Arrow with 2 lights lit up.
|
||||||
|
active2,
|
||||||
|
|
||||||
|
/// Arrow with 3 lights lit up.
|
||||||
|
active3,
|
||||||
|
|
||||||
|
/// Arrow with 4 lights lit up.
|
||||||
|
active4,
|
||||||
|
|
||||||
|
/// Arrow with all 5 lights lit up.
|
||||||
|
active5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicates if the blinking animation is running.
|
||||||
|
enum ArrowAnimationState {
|
||||||
|
idle,
|
||||||
|
blinking,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue