mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +08:00
111 lines
3.2 KiB
Dart
111 lines
3.2 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:meta/meta.dart';
|
|
|
|
import '../components/position_component.dart';
|
|
import 'effects.dart';
|
|
|
|
class CombinedEffect extends PositionComponentEffect {
|
|
final List<PositionComponentEffect> effects;
|
|
final double offset;
|
|
|
|
CombinedEffect({
|
|
@required this.effects,
|
|
this.offset = 0.0,
|
|
bool isInfinite = false,
|
|
bool isAlternating = false,
|
|
void Function() onComplete,
|
|
}) : super(
|
|
isInfinite,
|
|
isAlternating,
|
|
modifiesPosition: effects.any((e) => e.modifiesPosition),
|
|
modifiesAngle: effects.any((e) => e.modifiesAngle),
|
|
modifiesSize: effects.any((e) => e.modifiesSize),
|
|
onComplete: onComplete,
|
|
) {
|
|
assert(
|
|
effects.every((effect) => effect.component == null),
|
|
'Each effect can only be added once',
|
|
);
|
|
final types = effects.map((e) => e.runtimeType);
|
|
assert(
|
|
types.toSet().length == types.length,
|
|
"All effect types have to be different so that they don't clash",
|
|
);
|
|
}
|
|
|
|
@override
|
|
void initialize(PositionComponent component) {
|
|
super.initialize(component);
|
|
effects.forEach((effect) {
|
|
effect.initialize(component);
|
|
// Only change these if the effect modifies these
|
|
endPosition = effect.originalPosition != effect.endPosition
|
|
? effect.endPosition
|
|
: endPosition;
|
|
endAngle =
|
|
effect.originalAngle != effect.endAngle ? effect.endAngle : endAngle;
|
|
endSize =
|
|
effect.originalSize != effect.endSize ? effect.endSize : endSize;
|
|
peakTime = max(
|
|
peakTime,
|
|
effect.iterationTime + offset * effects.indexOf(effect),
|
|
);
|
|
});
|
|
if (isAlternating) {
|
|
endPosition = originalPosition;
|
|
endAngle = originalAngle;
|
|
endSize = originalSize;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void update(double dt) {
|
|
super.update(dt);
|
|
effects.forEach((effect) => _updateEffect(effect, dt));
|
|
if (effects.every((effect) => effect.hasCompleted())) {
|
|
if (isAlternating && curveDirection.isNegative) {
|
|
effects.forEach((effect) => effect.isAlternating = true);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
void reset() {
|
|
super.reset();
|
|
effects.forEach((effect) => effect.reset());
|
|
if (component != null) {
|
|
initialize(component);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
effects.forEach((effect) => effect.dispose());
|
|
}
|
|
|
|
void _updateEffect(PositionComponentEffect effect, double dt) {
|
|
final isReverse = curveDirection.isNegative;
|
|
final initialOffset = effects.indexOf(effect) * offset;
|
|
final effectOffset =
|
|
isReverse ? peakTime - effect.peakTime - initialOffset : initialOffset;
|
|
final passedOffset = isReverse ? peakTime - currentTime : currentTime;
|
|
if (!effect.hasCompleted() && effectOffset < passedOffset) {
|
|
final time =
|
|
effectOffset < passedOffset - dt ? dt : passedOffset - effectOffset;
|
|
effect.update(time);
|
|
}
|
|
if (isMax()) {
|
|
_maybeReverse(effect);
|
|
}
|
|
}
|
|
|
|
void _maybeReverse(PositionComponentEffect effect) {
|
|
if (isAlternating && !effect.isAlternating && effect.isMax()) {
|
|
// Make the effect go in reverse
|
|
effect.isAlternating = true;
|
|
}
|
|
}
|
|
}
|