feat: won trick ui

This commit is contained in:
2026-06-24 10:47:17 +03:30
parent 08937a66cb
commit e0d6763c00
3 changed files with 279 additions and 205 deletions
@@ -63,7 +63,8 @@ class HokmGame extends FlameGame {
// مدیریتِ ضربانِ قلب (فقط نوبتِ خودِ کاربر؛ مستقل از بازساختِ صحنه).
double _turnElapsed = 0;
bool _beatPlayed = false; // یک‌بار در هر نوبت، هنگام رسیدن به آستانه
bool _beatPlayed = false; // اولین ضربان در پنجره‌ی پایانیِ نوبت پخش شد
double _hbAccum = 0; // انباشتِ زمان برای تکرارِ منظمِ ضربان تا پایانِ نوبت
bool _wasMyTurn = false;
HokmGame(this.cubit, {this.skin = 'simple'});
@@ -271,16 +272,27 @@ class HokmGame extends FlameGame {
_wasMyTurn = true;
_turnElapsed = 0;
_beatPlayed = false;
_hbAccum = 0;
}
_turnElapsed += dt;
final dur = (s.turnTimeoutMs > 0 ? s.turnTimeoutMs / 1000.0 : 30.0);
final remaining = dur - _turnElapsed;
final warn = math.min(8.0, dur * 0.4);
// فقط یک‌بار، دقیقاً وقتی به آستانه‌ی پایانی رسیدیم.
if (!_beatPlayed && remaining > 0 && remaining <= warn) {
_beatPlayed = true;
AppSounds.heartBeat();
final warn = math.min(7.0, dur * 0.4);
// در پنجره‌ی پایانیِ نوبت، ضربان را با فاصله‌ی منظم تکرار کن تا تا لحظه‌ی
// آخر شنیده شود (نه فقط یک ضربانِ زودهنگام که در سکوتِ پایانی گم می‌شود).
if (remaining > 0 && remaining <= warn) {
if (!_beatPlayed) {
_beatPlayed = true;
_hbAccum = 0;
AppSounds.heartBeat();
} else {
_hbAccum += dt;
if (_hbAccum >= 0.95) {
_hbAccum = 0;
AppSounds.heartBeat();
}
}
}
}
@@ -524,32 +536,8 @@ class HokmGame extends FlameGame {
final count = seat < s.handCounts.length ? s.handCounts[seat] : 0;
_addBacks(_rel(seat), count);
}
_addTricksWon(s);
// امتیاز/نام/نشان/تاج/شمارنده‌ی نوبت اکنون در اوورلیِ Flutter (TableHud) کشیده
// می‌شوند تا متن واضح‌تر و چیدمان نزدیک به تصویرِ مرجع باشد.
}
// شمارنده ۱: دست‌های برده‌ی این هَند (tricks_won) — دسته‌کارتِ پشت‌رو + عدد.
// رسیدن به ۷ یعنی پایان هَند (سرور صفر می‌کند).
void _addTricksWon(GameState s) {
for (var team = 0; team < 2; team++) {
final won = team < s.tricksWon.length ? s.tricksWon[team] : 0;
if (won <= 0) continue;
final mine = team == s.yourSeat % 2;
final w = _cardW * 0.40, h = w * kCardRatio;
// تیم شما جلوی شما (پایین)، تیم حریف جلوی حریفِ سمت راست.
final base =
mine
? Vector2(size.x * 0.28, size.y * 0.72)
: Vector2(size.x * 0.82, size.y * 0.24);
final step = Vector2(w * 0.40, 0);
final n = won.clamp(1, 7);
final start = base - step * ((n - 1) / 2);
for (var i = 0; i < n; i++) {
_addBack(start + step * i.toDouble(), Vector2(w, h), priority: 2);
}
_addLabel('$won', base - Vector2(0, h * 0.7), _cardW * 0.34, bold: true);
}
// امتیاز/نام/نشان/تاج/شمارنده‌ی نوبت و دست‌های برده (tricks_won) اکنون در
// اوورلیِ Flutter (TableHud) نمایش داده می‌شوند تا واضح‌تر و کم‌شلوغ‌تر باشند.
}
// پشت‌کارت‌های یک حریف به‌صورت بادبزنی.
@@ -559,67 +547,47 @@ class HokmGame extends FlameGame {
final w = _cardW * 0.7, h = _cardH * 0.7;
final c = size / 2;
Vector2 base, stepV;
double angle = 0; // کارت‌های کناری ۹۰° می‌چرخند تا «به‌سمتِ» بازیکنِ کنار باشند
switch (rel) {
case 2:
base = Vector2(c.x, size.y * 0.12);
stepV = Vector2(size.x * 0.45 / 13, 0);
break;
case 1:
base = Vector2(size.x * 0.07, c.y);
stepV = Vector2(0, size.y * 0.4 / 13);
// مرکزِ کارت روی لبه‌ی چپ ⇒ فقط نیمه‌ی داخلیِ کارت دیده می‌شود (شلوغیِ کمتر).
base = Vector2(0, c.y);
stepV = Vector2(0, size.y * 0.36 / 13);
angle = math.pi / 2;
break;
default:
base = Vector2(size.x * 0.93, c.y);
stepV = Vector2(0, size.y * 0.4 / 13);
base = Vector2(size.x, c.y);
stepV = Vector2(0, size.y * 0.36 / 13);
angle = -math.pi / 2;
}
final start = base - stepV * ((n - 1) / 2);
for (var i = 0; i < n; i++) {
_addBack(start + stepV * i.toDouble(), Vector2(w, h), priority: 1);
_addBack(start + stepV * i.toDouble(), Vector2(w, h),
priority: 1, angle: angle);
}
}
// ===== کمکی‌های ساختِ عنصر (ثبت در فهرستِ بازساخته‌شونده) =====
void _addBack(Vector2 pos, Vector2 sz, {required int priority}) {
void _addBack(Vector2 pos, Vector2 sz,
{required int priority, double angle = 0}) {
final c = CardComponent(
code: '',
faceUp: false,
skin: skin,
size: sz,
position: pos,
angle: angle,
priority: priority,
);
_backs.add(c);
add(c);
}
void _addLabel(
String text,
Vector2 pos,
double fontSize, {
Color color = const Color(0xFFE9B949),
Anchor anchor = Anchor.center,
bool bold = false,
}) {
final t = TextComponent(
text: text,
anchor: anchor,
position: pos,
priority: 21,
textRenderer: TextPaint(
style: TextStyle(
fontFamily: 'Dana',
color: color,
fontSize: fontSize,
fontWeight: bold ? FontWeight.bold : FontWeight.normal,
shadows: const [Shadow(color: Colors.black, blurRadius: 4)],
),
),
);
_info.add(t);
add(t);
}
(String, Color) _trumpGlyph(String suit) {
switch (suit) {
case 'hearts':