import 'dart:math' as math; import 'package:flutter/material.dart'; /// بارشِ کاغذرنگی (کانفتی) سبک و بدونِ وابستگی — برای صفحه‌ی بردِ بازی. class Confetti extends StatefulWidget { final int count; const Confetti({super.key, this.count = 60}); @override State createState() => _ConfettiState(); } class _ConfettiState extends State with SingleTickerProviderStateMixin { late final AnimationController _c; late final List<_Piece> _pieces; static const _colors = [ Color(0xFFE9B949), // طلایی Color(0xFF1E5FA8), // لاجوردی Color(0xFFB81D2A), // شنگرف Color(0xFF3FA34D), // سبز Color(0xFFFFFFFF), ]; @override void initState() { super.initState(); final r = math.Random(); _pieces = List.generate(widget.count, (_) { return _Piece( x: r.nextDouble(), delay: r.nextDouble() * 0.5, speed: 0.7 + r.nextDouble() * 0.6, drift: (r.nextDouble() - 0.5) * 0.4, size: 6 + r.nextDouble() * 7, color: _colors[r.nextInt(_colors.length)], rot: r.nextDouble() * math.pi, rotSpeed: (r.nextDouble() - 0.5) * 12, round: r.nextBool(), ); }); _c = AnimationController( vsync: this, duration: const Duration(milliseconds: 2600), )..forward(); } @override void dispose() { _c.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return IgnorePointer( child: AnimatedBuilder( animation: _c, builder: (_, __) => CustomPaint( size: Size.infinite, painter: _ConfettiPainter(_pieces, _c.value), ), ), ); } } class _Piece { final double x, delay, speed, drift, size, rot, rotSpeed; final Color color; final bool round; _Piece({ required this.x, required this.delay, required this.speed, required this.drift, required this.size, required this.color, required this.rot, required this.rotSpeed, required this.round, }); } class _ConfettiPainter extends CustomPainter { final List<_Piece> pieces; final double t; // ۰..۱ _ConfettiPainter(this.pieces, this.t); @override void paint(Canvas canvas, Size size) { for (final p in pieces) { final local = ((t - p.delay) * p.speed).clamp(0.0, 1.0); if (local <= 0) continue; final y = -0.1 + local * 1.25; final x = (p.x + p.drift * local) * size.width; final py = y * size.height; final opacity = (1.0 - local).clamp(0.0, 1.0); final paint = Paint()..color = p.color.withValues(alpha: opacity); canvas.save(); canvas.translate(x, py); canvas.rotate(p.rot + p.rotSpeed * local); if (p.round) { canvas.drawCircle(Offset.zero, p.size / 2, paint); } else { canvas.drawRect( Rect.fromCenter(center: Offset.zero, width: p.size, height: p.size * 0.6), paint, ); } canvas.restore(); } } @override bool shouldRepaint(covariant _ConfettiPainter old) => old.t != t; }