handleTouchInteraction method

void handleTouchInteraction(
  1. Canvas canvas,
  2. List<int> visibleParticles
)

Handles both touch physics and rendering in a single optimized pass

This method:

  1. Calculates distance once per particle
  2. Applies physics to nearby particles
  3. Batches rendering into opacity buckets

canvas - The canvas to draw on visibleParticles - List of indices of currently visible particles

Implementation

void handleTouchInteraction(Canvas canvas, List<int> visibleParticles) {
  final Offset? touch = touchPoint;
  if (touch == null) return;

  // Pre-calculate touch position components for faster access
  final double touchX = touch.dx;
  final double touchY = touch.dy;

  // Buckets for batched rendering (10 opacity levels)
  final List<List<Offset>> opacityBuckets = List.generate(10, (_) => []);

  for (final int i in visibleParticles) {
    final Particle p = particles[i];

    // Calculate distance once using inline math (avoids intermediate Offset)
    final double dx = p.position.dx - touchX;
    final double dy = p.position.dy - touchY;
    final double distance = math.sqrt(dx * dx + dy * dy);

    if (distance < lineDistance) {
      // Apply physics: pull particle towards touch point
      const double force = 0.00111;
      final double pullX = -dx * force;
      final double pullY = -dy * force;
      p.velocity += Offset(pullX, pullY);
      p.wasAccelerated = true;

      // Prepare for batched rendering
      final double opacity = 1.0 - (distance / lineDistance);
      if (opacity > 0) {
        final int bucketIndex = (opacity * 9).floor().clamp(0, 9);
        opacityBuckets[bucketIndex].add(p.position);
        opacityBuckets[bucketIndex].add(touch);
      }
    }
  }

  // Batch render all touch lines by opacity level
  for (int i = 0; i < 10; i++) {
    final List<Offset> points = opacityBuckets[i];
    if (points.isNotEmpty) {
      final double bucketOpacity = (i + 1) / 10.0;
      linePaint.color = touchColor.withOpacity(bucketOpacity);
      canvas.drawPoints(PointMode.lines, points, linePaint);
    }
  }
}