paint method

  1. @override
void paint(
  1. Canvas cv,
  2. Size size,
  3. double progress,
  4. Offset center,
  5. Color color, {
  6. double radiusMultiplier = 1.0,
  7. Offset positionOffset = Offset.zero,
})
override

Implementation

@override
void paint(Canvas cv, Size size, double progress, Offset center, Color color,
    {double radiusMultiplier = 1.0, Offset positionOffset = Offset.zero}) {
  final c = center + positionOffset;
  final rnd = math.Random(42);
  final minSide = math.min(size.width, size.height);

  final explosionRadius = minSide * explosionScale * radiusMultiplier;

  // sudut tetap
  final angles = List<double>.generate(
    particleCount,
    (i) => useUniformAngle
        ? (i / particleCount) * 2 * math.pi
        : rnd.nextDouble() * 2 * math.pi,
  );

  for (int i = 0; i < particleCount; i++) {
    final delay = i * 0.02; // partikel muncul bergiliran
    final rawT = progress - delay;
    if (rawT <= 0) continue;

    // normalisasi supaya selesai saat progress==1
    final t = (rawT / (1 - delay)).clamp(0.0, 1.0);
    final angle = angles[i];

    // ─── posisi radial ───
    double dist;
    if (t < _tailGrowEnd) {
      // belum jauh dari pusat
      dist = explosionRadius * .1; // 10 % jarak akhir
    } else {
      final tt = (t - _tailGrowEnd) / (1 - _tailGrowEnd); // 0‑1
      dist = explosionRadius * _easeOutBack(tt);
    }
    final pos = c + Offset(math.cos(angle), math.sin(angle)) * dist;

    // ─── tail length ───
    double tailLen;
    if (t < _dotSpawnEnd) {
      tailLen = 0;
    } else if (t < _tailGrowEnd) {
      final tailT = (t - _dotSpawnEnd) / (_tailGrowEnd - _dotSpawnEnd);
      tailLen = circleRadius *
          tailFactor *
          tailT *
          radiusMultiplier; // tumbuh 0→penuh
    } else {
      tailLen = circleRadius * tailFactor * radiusMultiplier;
    }

    // ─── skala & opasitas dot ───
    double scale;
    double opacity;
    if (t < _dotSpawnEnd) {
      scale = t / _dotSpawnEnd; // grow‑in
      opacity = scale;
    } else if (t > .85) {
      scale = 1 - (t - .85) / .15 * .3; // sedikit mengecil
      opacity = 1 - (t - .85) / .15; // fade‑out
    } else {
      scale = 1.0;
      opacity = 1.0;
    }

    // ─── warna ───
    Color col = color;
    if (enableHueTilt) {
      final hsl = HSLColor.fromColor(color);
      final shift = (angle / (2 * math.pi)) * 360 * hueTiltRange;
      col = hsl
          .withHue((hsl.hue + shift) % 360)
          .withSaturation((hsl.saturation * saturationBoost).clamp(0, 1))
          .toColor();
    }
    col = col.withOpacity(opacity.toDouble());

    // ─── gambar dot ───
    final rad = circleRadius * radiusMultiplier * scale;
    cv.drawCircle(pos, rad, Paint()..color = col);

    // ─── gambar tail ───
    if (tailLen > 0) {
      final tailStart =
          pos - Offset(math.cos(angle), math.sin(angle)) * tailLen;
      cv.drawLine(
          tailStart,
          pos,
          Paint()
            ..color = col
            ..strokeWidth = rad * .8
            ..strokeCap = StrokeCap.round);
    }
  }
}