handleTouchInteraction method
Handles both touch physics and rendering in a single optimized pass
This method:
- Calculates distance once per particle
- Applies physics to nearby particles
- 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);
}
}
}