Line data Source code
1 : import 'dart:math'; 2 : import 'dart:ui'; 3 : 4 : import '../components/position_component.dart'; 5 : import 'effects.dart'; 6 : 7 : class CombinedEffect extends PositionComponentEffect { 8 : final List<PositionComponentEffect> effects; 9 : final double offset; 10 : 11 1 : CombinedEffect({ 12 : required this.effects, 13 : this.offset = 0.0, 14 : bool isInfinite = false, 15 : bool isAlternating = false, 16 : VoidCallback? onComplete, 17 1 : }) : super( 18 : isInfinite, 19 : isAlternating, 20 3 : modifiesPosition: effects.any((e) => e.modifiesPosition), 21 3 : modifiesAngle: effects.any((e) => e.modifiesAngle), 22 3 : modifiesSize: effects.any((e) => e.modifiesSize), 23 : onComplete: onComplete, 24 : ) { 25 : assert( 26 4 : effects.every((effect) => effect.component == null), 27 : 'Each effect can only be added once', 28 : ); 29 4 : final types = effects.map((e) => e.runtimeType); 30 : assert( 31 4 : types.toSet().length == types.length, 32 : "All effect types have to be different so that they don't clash", 33 : ); 34 : } 35 : 36 1 : @override 37 : void initialize(PositionComponent component) { 38 1 : super.initialize(component); 39 3 : effects.forEach((effect) { 40 1 : effect.initialize(component); 41 : // Only change these if the effect modifies these 42 4 : endPosition = effect.originalPosition != effect.endPosition 43 1 : ? effect.endPosition 44 1 : : endPosition; 45 1 : endAngle = 46 5 : effect.originalAngle != effect.endAngle ? effect.endAngle : endAngle; 47 1 : endSize = 48 5 : effect.originalSize != effect.endSize ? effect.endSize : endSize; 49 2 : peakTime = max( 50 1 : peakTime, 51 6 : effect.iterationTime + offset * effects.indexOf(effect), 52 : ); 53 : }); 54 1 : if (isAlternating) { 55 2 : endPosition = originalPosition; 56 2 : endAngle = originalAngle; 57 2 : endSize = originalSize; 58 : } 59 : } 60 : 61 1 : @override 62 : void update(double dt) { 63 1 : super.update(dt); 64 4 : effects.forEach((effect) => _updateEffect(effect, dt)); 65 4 : if (effects.every((effect) => effect.hasCompleted())) { 66 3 : if (isAlternating && curveDirection.isNegative) { 67 4 : effects.forEach((effect) => effect.isAlternating = true); 68 : } 69 : } 70 : } 71 : 72 1 : @override 73 : void reset() { 74 1 : super.reset(); 75 4 : effects.forEach((effect) => effect.reset()); 76 1 : if (component != null) { 77 2 : initialize(component!); 78 : } 79 : } 80 : 81 0 : @override 82 : void dispose() { 83 0 : super.dispose(); 84 0 : effects.forEach((effect) => effect.dispose()); 85 : } 86 : 87 1 : void _updateEffect(PositionComponentEffect effect, double dt) { 88 2 : final isReverse = curveDirection.isNegative; 89 4 : final initialOffset = effects.indexOf(effect) * offset; 90 : final effectOffset = 91 3 : isReverse ? peakTime - effect.peakTime - initialOffset : initialOffset; 92 1 : final passedOffset = isReverse ? peakTime - currentTime : currentTime; 93 2 : if (!effect.hasCompleted() && effectOffset < passedOffset) { 94 : final time = 95 3 : effectOffset < passedOffset - dt ? dt : passedOffset - effectOffset; 96 1 : effect.update(time); 97 : } 98 1 : if (isMax()) { 99 1 : _maybeReverse(effect); 100 : } 101 : } 102 : 103 1 : void _maybeReverse(PositionComponentEffect effect) { 104 3 : if (isAlternating && !effect.isAlternating && effect.isMax()) { 105 : // Make the effect go in reverse 106 1 : effect.isAlternating = true; 107 : } 108 : } 109 : }