import 'package:flame/components.dart'; import 'package:flame/effects.dart'; import 'package:flutter/material.dart'; /// انیمیشنِ پخشِ کارت. /// - حالتِ بُر زدن ([dealOnly]=false): دو دسته در مرکز ریفل و سپس پخش می‌شوند. /// - حالتِ پخش ([dealOnly]=true): کارت‌ها از مرکز به سمتِ چهار بازیکن پخش می‌شوند /// (پس از انتخابِ حکم، برای پخشِ بقیه‌ی کارت‌ها). class ShuffleAnimation extends PositionComponent { final Vector2 area; final bool dealOnly; ShuffleAnimation(this.area, {this.dealOnly = false}); /// مدتِ کلِ هر حالت (مرجعِ هماهنگیِ صدا). static const int totalMs = 2000; static const int dealMs = 1300; @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 stack = center + Vector2((i - n / 2) * cw * 0.05, 0); final delay = i * 0.02; if (dealOnly) { // فقط پخش: از یک دسته‌ی مرتب در مرکز به سمتِ بازیکن‌ها. final card = _Back(Vector2(cw, ch)) ..anchor = Anchor.center ..position = stack; add(card); card.add(MoveToEffect( center + dirs[i % 4], EffectController( duration: 0.45, curve: Curves.easeIn, startDelay: 0.15 + delay), )); card.add(ScaleEffect.to( Vector2.all(0.5), EffectController(duration: 0.45, startDelay: 0.15 + delay), )); continue; } // حالتِ بُر زدن: ریفل سپس پخش. final left = i.isEven; 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: (dealOnly ? dealMs : 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); } }