effect_line.dart 5.73 KB
Newer Older
1
part of flutter_sprites;
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

enum EffectLineWidthMode {
  linear,
  barrel,
}

enum EffectLineAnimationMode {
  none,
  scroll,
  random,
}

class EffectLine extends Node {

  EffectLine({
    this.texture: null,
18
    this.transferMode: TransferMode.dstOver,
19 20 21 22
    List<Point> points,
    this.widthMode : EffectLineWidthMode.linear,
    this.minWidth: 10.0,
    this.maxWidth: 10.0,
23
    this.widthGrowthSpeed: 0.0,
24 25
    this.animationMode: EffectLineAnimationMode.none,
    this.scrollSpeed: 0.1,
26
    double scrollStart: 0.0,
27 28 29 30 31 32
    this.fadeDuration: null,
    this.fadeAfterDelay: null,
    this.textureLoopLength: null,
    this.simplify: true,
    ColorSequence colorSequence
  }) {
Hixie's avatar
Hixie committed
33 34 35 36
    if (points == null)
      this.points = <Point>[];
    else
      this.points = points;
37 38

    _colorSequence = colorSequence;
Hixie's avatar
Hixie committed
39
    if (_colorSequence == null) {
40
      _colorSequence = new ColorSequence.fromStartAndEndColor(
41 42
        const Color(0xffffffff),
        const Color(0xffffffff)
Hixie's avatar
Hixie committed
43 44
      );
    }
45

46 47
    _offset = scrollStart;

48 49 50 51 52 53
    _painter = new TexturedLinePainter(points, _colors, _widths, texture);
    _painter.textureLoopLength = textureLoopLength;
  }

  final Texture texture;

54
  final TransferMode transferMode;
55

56 57 58
  final EffectLineWidthMode widthMode;
  final double minWidth;
  final double maxWidth;
59
  final double widthGrowthSpeed;
60 61 62 63 64 65 66 67 68 69

  final EffectLineAnimationMode animationMode;
  final double scrollSpeed;
  ColorSequence _colorSequence;
  ColorSequence get colorSequence => _colorSequence;

  List<Point> _points;

  List<Point> get points => _points;

70
  void set points(List<Point> points) {
71
    _points = points;
Hixie's avatar
Hixie committed
72
    _pointAges = <double>[];
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    for (int i = 0; i < _points.length; i++) {
      _pointAges.add(0.0);
    }
  }

  List<double> _pointAges;
  List<Color> _colors;
  List<double> _widths;

  final double fadeDuration;
  final double fadeAfterDelay;

  final double textureLoopLength;

  final bool simplify;

  TexturedLinePainter _painter;
  double _offset = 0.0;

  void update(double dt) {
    // Update scrolling position
    if (animationMode == EffectLineAnimationMode.scroll) {
      _offset += dt * scrollSpeed;
      _offset %= 1.0;
    } else if (animationMode == EffectLineAnimationMode.random) {
      _offset = randomDouble();
    }

101
    // Update age of line points and remove if neccesasry
102
    if (fadeDuration != null && fadeAfterDelay != null) {
103
      // Increase age of points
104 105
      for (int i = _points.length - 1; i >= 0; i--) {
        _pointAges[i] += dt;
106 107 108 109 110 111
      }

      // Check if the first/oldest point should be removed
      while(_points.length > 0 && _pointAges[0] > (fadeDuration + fadeAfterDelay)) {
        // Update scroll if it isn't the last and only point that is about to removed
        if (_points.length > 1 && textureLoopLength != null) {
112
          double dist = GameMath.distanceBetweenPoints(_points[0], _points[1]);
113 114
          _offset = (_offset - (dist / textureLoopLength)) % 1.0;
          if (_offset < 0.0) _offset += 1;
115
        }
116 117 118 119

        // Remove the point
        _pointAges.removeAt(0);
        _points.removeAt(0);
120 121 122 123
      }
    }
  }

Adam Barth's avatar
Adam Barth committed
124
  void paint(Canvas canvas) {
125 126 127 128 129 130 131
    if (points.length < 2) return;

    _painter.points = points;

    // Calculate colors
    List<double> stops = _painter.calculatedTextureStops;

Hixie's avatar
Hixie committed
132
    List<Color> colors = <Color>[];
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    for (int i = 0; i < stops.length; i++) {
      double stop = stops[i];
      Color color = _colorSequence.colorAtPosition(stop);

      if (fadeDuration != null && fadeAfterDelay != null) {
        double age = _pointAges[i];
        if (age > fadeAfterDelay) {
          double fade = 1.0 - (age - fadeAfterDelay) / fadeDuration;
          int alpha = (color.alpha * fade).toInt().clamp(0, 255);
          color = new Color.fromARGB(alpha, color.red, color.green, color.blue);
        }
      }
      colors.add(color);
    }
    _painter.colors = colors;

    // Calculate widths
Hixie's avatar
Hixie committed
150
    List<double> widths = <double>[];
151 152 153
    for (int i = 0; i < stops.length; i++) {
      double stop = stops[i];
      double growth = math.max(widthGrowthSpeed * _pointAges[i], 0.0);
154
      if (widthMode == EffectLineWidthMode.linear) {
155
        double width = minWidth + (maxWidth - minWidth) * stop + growth;
156 157
        widths.add(width);
      } else if (widthMode == EffectLineWidthMode.barrel) {
158
        double width = minWidth + math.sin(stop * math.PI) * (maxWidth - minWidth) + growth;
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
        widths.add(width);
      }
    }
    _painter.widths = widths;

    _painter.textureStopOffset = _offset;

    _painter.paint(canvas);
  }

  void addPoint(Point point) {
    // Skip duplicate points
    if (points.length > 0 && point.x == points[points.length - 1].x && point.y == points[points.length - 1].y)
      return;

174
    if (simplify && points.length >= 2 && GameMath.distanceBetweenPoints(point, points[points.length - 2]) < 10.0) {
175 176 177 178 179 180 181 182 183
      // Check if we should remove last point before adding the new one

      // Calculate the square distance from the middle point to the line of the
      // new point and the second to last point
      double dist2 = _distToSeqment2(
        points[points.length - 1],
        point,
        points[points.length - 2]
      );
184

185 186 187 188
      // If the point is on the line, remove it
      if (dist2 < 1.0) {
        _points.removeAt(_points.length - 1);
      }
189 190 191 192 193 194
    }

    // Add point and point's age
    _points.add(point);
    _pointAges.add(0.0);
  }
195 196 197 198 199 200 201 202 203 204 205 206 207

  double _sqr(double x) => x * x;

  double _dist2(Point v, Point w) => _sqr(v.x - w.x) + _sqr(v.y - w.y);

  double _distToSeqment2(Point p, Point v, Point w) {
    double l2 = _dist2(v, w);
    if (l2 == 0.0) return _dist2(p, v);
    double t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
    if (t < 0) return _dist2(p, v);
    if (t > 1) return _dist2(p, w);
    return _dist2(p, new Point(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y)));
  }
208
}