113 lines
3.9 KiB
Dart
113 lines
3.9 KiB
Dart
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<void> 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);
|
|
}
|
|
}
|