Line data Source code
1 : import 'dart:ui'; 2 : 3 : import '../components/position_component.dart'; 4 : import 'effects.dart'; 5 : 6 : class SequenceEffect extends PositionComponentEffect { 7 : final List<PositionComponentEffect> effects; 8 : late PositionComponentEffect currentEffect; 9 : late bool _currentWasAlternating; 10 : 11 : static const int _initialIndex = 0; 12 : static const double _initialDriftModifier = 0.0; 13 : 14 : int _currentIndex = _initialIndex; 15 : double _driftModifier = _initialDriftModifier; 16 : 17 1 : SequenceEffect({ 18 : required this.effects, 19 : bool isInfinite = false, 20 : bool isAlternating = false, 21 : VoidCallback? onComplete, 22 1 : }) : super( 23 : isInfinite, 24 : isAlternating, 25 3 : modifiesPosition: effects.any((e) => e.modifiesPosition), 26 3 : modifiesAngle: effects.any((e) => e.modifiesAngle), 27 3 : modifiesSize: effects.any((e) => e.modifiesSize), 28 : onComplete: onComplete, 29 : ) { 30 : assert( 31 4 : effects.every((effect) => effect.component == null), 32 : 'Each effect can only be added once', 33 : ); 34 : assert( 35 4 : effects.every((effect) => !effect.isInfinite), 36 : 'No effects added to the sequence can be infinite', 37 : ); 38 : } 39 : 40 1 : @override 41 : void initialize(PositionComponent component) { 42 1 : super.initialize(component); 43 1 : _currentIndex = _initialIndex; 44 1 : _driftModifier = _initialDriftModifier; 45 : 46 3 : effects.forEach((effect) { 47 1 : effect.reset(); 48 3 : component.position.setFrom(endPosition!); 49 2 : component.angle = endAngle!; 50 3 : component.size.setFrom(endSize!); 51 1 : effect.initialize(component); 52 2 : endPosition = effect.endPosition; 53 2 : endAngle = effect.endAngle; 54 2 : endSize = effect.endSize; 55 : }); 56 : // Add all the effects iteration time since they can alternate within the 57 : // sequence effect 58 3 : peakTime = effects.fold( 59 : 0, 60 3 : (time, effect) => time + effect.iterationTime, 61 : ); 62 1 : if (isAlternating) { 63 2 : endPosition = originalPosition; 64 2 : endAngle = originalAngle; 65 2 : endSize = originalSize; 66 : } 67 3 : component.position.setFrom(originalPosition!); 68 2 : component.angle = originalAngle!; 69 3 : component.size.setFrom(originalSize!); 70 3 : currentEffect = effects.first; 71 3 : _currentWasAlternating = currentEffect.isAlternating; 72 : } 73 : 74 1 : @override 75 : void update(double dt) { 76 1 : super.update(dt); 77 : 78 : // If the last effect's time to completion overshot its total time, add that 79 : // time to the first time step of the next effect. 80 4 : currentEffect.update(dt + _driftModifier); 81 1 : _driftModifier = 0.0; 82 2 : if (currentEffect.hasCompleted()) { 83 2 : currentEffect.setComponentToEndState(); 84 3 : _driftModifier = currentEffect.driftTime; 85 2 : _currentIndex++; 86 : final orderedEffects = 87 6 : curveDirection.isNegative ? effects.reversed.toList() : effects; 88 : // Make sure the current effect has the `isAlternating` value it 89 : // initially started with 90 3 : currentEffect.isAlternating = _currentWasAlternating; 91 : // Get the next effect that should be executed 92 6 : currentEffect = orderedEffects[_currentIndex % effects.length]; 93 : // Keep track of what value of `isAlternating` the effect had from the 94 : // start 95 3 : _currentWasAlternating = currentEffect.isAlternating; 96 1 : if (isAlternating && 97 2 : !currentEffect.isAlternating && 98 2 : curveDirection.isNegative) { 99 : // Make the effect go in reverse 100 2 : currentEffect.isAlternating = true; 101 : } 102 : } 103 : } 104 : 105 1 : @override 106 : void reset() { 107 1 : super.reset(); 108 4 : effects.forEach((e) => e.reset()); 109 1 : if (component != null) { 110 2 : initialize(component!); 111 : } 112 : } 113 : }