import 'package:flame/components.dart'; import 'package:flame/effects.dart'; import 'package:flutter/material.dart'; /// انیمیشنِ بُر زدن: دو دسته کارتِ پشت‌رو در مرکز ریفل می‌شوند، کمی بالا/پایین /// می‌روند (بُر) و سپس به سمت چهار بازیکن پخش می‌شوند. مدتِ کل [totalMs] است /// تا صدای بُر زدن دقیقاً هم‌زمان با پایانِ انیمیشن قطع شود. class ShuffleAnimation extends PositionComponent { final Vector2 area; ShuffleAnimation(this.area); /// مدتِ کلِ انیمیشن (مرجعِ هماهنگیِ صدا). static const int totalMs = 2000; @override Future onLoad() async { priority = 6000; final cw = area.x * 0.16; final ch = cw * 1.45; final center = Vector2(area.x / 2, area.y / 2); const n = 10; // جهتِ پخش به سمتِ ۴ بازیکن (پایین، چپ، بالا، راست). final dirs = [ Vector2(0, area.y * 0.42), Vector2(-area.x * 0.42, 0), Vector2(0, -area.y * 0.42), Vector2(area.x * 0.42, 0), ]; for (var i = 0; i < n; i++) { final left = i.isEven; final stack = center + Vector2((i - n / 2) * cw * 0.05, 0); final delay = i * 0.02; // ریفلِ پلکانی final card = _Back(Vector2(cw, ch)) ..anchor = Anchor.center ..position = center + Vector2((left ? -1 : 1) * cw, 0) ..angle = (left ? -1 : 1) * 0.22; add(card); // صاف‌شدنِ زاویه هم‌زمان با ریفل. card.add(RotateEffect.to( 0, EffectController(duration: 0.55, startDelay: delay))); // دنباله: ریفل به مرکز ← بالا (بُر) ← نشستن ← پخش به سمت بازیکن. card.add(SequenceEffect([ MoveToEffect(stack, EffectController(duration: 0.55, curve: Curves.easeOut, startDelay: delay)), MoveToEffect(stack + Vector2(0, -ch * 0.18), EffectController(duration: 0.35, curve: Curves.easeInOut)), MoveToEffect(stack, EffectController(duration: 0.35, curve: Curves.easeInOut)), MoveToEffect(center + dirs[i % 4], EffectController(duration: 0.55, curve: Curves.easeIn)), ])); // کوچک‌شدن هنگامِ پخش (هم‌زمان با حرکتِ آخرِ دنباله). card.add(ScaleEffect.to( Vector2.all(0.5), EffectController(duration: 0.55, startDelay: 1.25 + delay), )); } add(RemoveEffect(delay: totalMs / 1000)); } } /// پشتِ یک کارت (مستطیلِ گرد با حاشیه‌ی طلایی). class _Back extends PositionComponent { _Back(Vector2 s) : super(size: s); static final _fill = Paint()..color = const Color(0xFF7A1020); static final _border = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 2 ..color = const Color(0xFFE9C76A); static final _inner = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 1.5 ..color = const Color(0x88E9C76A); @override void render(Canvas canvas) { final rect = size.toRect(); canvas.drawRRect( RRect.fromRectAndRadius(rect, const Radius.circular(8)), _fill); canvas.drawRRect( RRect.fromRectAndRadius(rect, const Radius.circular(8)), _border); canvas.drawRRect( RRect.fromRectAndRadius(rect.deflate(6), const Radius.circular(6)), _inner); } }