feat: phase 1 of improve
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
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<Confetti> createState() => _ConfettiState();
|
||||
}
|
||||
|
||||
class _ConfettiState extends State<Confetti> 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;
|
||||
}
|
||||
Reference in New Issue
Block a user