priority of cards fixed
This commit is contained in:
@@ -49,9 +49,16 @@ class HokmGame extends FlameGame {
|
||||
bool _introActive = true; // تا پایانِ نمایشِ «جستجوی حریف»
|
||||
bool _pendingShuffle =
|
||||
false; // بُرِ دستِ اول که تا پایانِ اینترو به تعویق افتاده
|
||||
bool _shuffling = false; // در حالِ پخشِ انیمیشنِ بُر زدن (بازیِ کارت ممنوع)
|
||||
bool _shuffling = false; // در حالِ بُر زدن/پخشِ ۵ کارت (بازیِ کارت ممنوع)
|
||||
bool _dealing = false; // در حالِ پخشِ بقیهی کارتها پس از حکم (بازی ممنوع)
|
||||
String? _prevTrump; // برای تشخیصِ لحظهی انتخابِ حکم
|
||||
|
||||
/// آیا انیمیشنی در حال اجراست (اینترو/بُر زدن/پخشِ کارت). صفحه از این برای
|
||||
/// پنهانکردنِ دیالوگِ انتخابِ حکم تا پایانِ پخشِ کارتها استفاده میکند.
|
||||
final ValueNotifier<bool> animating = ValueNotifier(true);
|
||||
void _refreshAnimating() =>
|
||||
animating.value = _introActive || _shuffling || _dealing;
|
||||
|
||||
// مدیریتِ ضربانِ قلب (فقط نوبتِ خودِ کاربر؛ مستقل از بازساختِ صحنه).
|
||||
double _turnElapsed = 0;
|
||||
bool _beatPlayed = false; // یکبار در هر نوبت، هنگام رسیدن به آستانه
|
||||
@@ -83,6 +90,7 @@ class HokmGame extends FlameGame {
|
||||
if (_prevTrump == null && s.trump != null && !_silent) {
|
||||
AppSounds.selectHokm();
|
||||
_spawnTrumpReveal(s.trump!);
|
||||
_dealAllNow(); // پخشِ بقیهی کارتها (بازی تا پایانِ آن قفل است)
|
||||
}
|
||||
_prevTrump = s.trump;
|
||||
_prevHandSize = s.yourHand.length;
|
||||
@@ -117,7 +125,8 @@ class HokmGame extends FlameGame {
|
||||
// شمشیر + تکان + رعد)؛ خالیشدنِ زمین ⇒ صدای جمعشدنِ دست.
|
||||
void _checkTrickSounds(GameState s) {
|
||||
final now = s.trick.map((t) => t.card).toList();
|
||||
if (_silent) {
|
||||
// در زمانِ اینترو/بُر زدن/پخش، کارتی روی میز نشان داده نمیشود ⇒ صدا هم نه.
|
||||
if (_silent || _introActive || _shuffling || _dealing) {
|
||||
_prevTrick = now;
|
||||
return;
|
||||
}
|
||||
@@ -157,6 +166,7 @@ class HokmGame extends FlameGame {
|
||||
_pendingShuffle = false;
|
||||
_shuffleNow();
|
||||
}
|
||||
_refreshAnimating();
|
||||
}
|
||||
|
||||
/// اجرای همزمانِ انیمیشن و صدای بُر زدن (صدا با پایانِ انیمیشن قطع میشود).
|
||||
@@ -166,12 +176,28 @@ class HokmGame extends FlameGame {
|
||||
AppSounds.shuffle(cutoffMs: ShuffleAnimation.totalMs);
|
||||
add(ShuffleAnimation(size));
|
||||
_shuffling = true;
|
||||
_refreshAnimating();
|
||||
Future.delayed(const Duration(milliseconds: ShuffleAnimation.totalMs), () {
|
||||
_shuffling = false;
|
||||
_refreshAnimating();
|
||||
if (_s != null && !_silent) _relayout(); // فعالسازیِ دوبارهی کارتها
|
||||
});
|
||||
}
|
||||
|
||||
/// پخشِ بقیهی کارتها پس از انتخابِ حکم؛ تا پایانِ انیمیشن بازیِ کارت قفل است.
|
||||
void _dealAllNow() {
|
||||
if (_silent) return;
|
||||
AppSounds.shuffle(cutoffMs: ShuffleAnimation.dealMs);
|
||||
add(ShuffleAnimation(size, dealOnly: true));
|
||||
_dealing = true;
|
||||
_refreshAnimating();
|
||||
Future.delayed(const Duration(milliseconds: ShuffleAnimation.dealMs), () {
|
||||
_dealing = false;
|
||||
_refreshAnimating();
|
||||
if (_s != null && !_silent) _relayout();
|
||||
});
|
||||
}
|
||||
|
||||
/// نمایشِ بزرگ و گذرای حکمِ انتخابشده در مرکزِ میز (با پاپ).
|
||||
void _spawnTrumpReveal(String trump) {
|
||||
final (sym, col) = _trumpGlyph(trump);
|
||||
@@ -286,8 +312,8 @@ class HokmGame extends FlameGame {
|
||||
// آیا این کارت در نوبتِ فعلی قابل بازی است (با رعایت follow-suit)؟
|
||||
bool _legal(String code) {
|
||||
final s = _s!;
|
||||
// هنگامِ نمایشِ اینترو یا انیمیشنِ بُر زدن، بازیِ کارت مجاز نیست.
|
||||
if (_introActive || _shuffling) return false;
|
||||
// هنگامِ اینترو/بُر زدن/پخشِ کارتها، بازیِ کارت مجاز نیست.
|
||||
if (_introActive || _shuffling || _dealing) return false;
|
||||
if (s.phase != 'playing' || s.trickDone || !s.isMyTurn) return false;
|
||||
final lead = s.leadSuit;
|
||||
if (lead == null || lead.isEmpty) return true;
|
||||
@@ -317,6 +343,15 @@ class HokmGame extends FlameGame {
|
||||
Rect.fromLTRB(size.x * 0.15, size.y * 0.22, size.x * 0.85, size.y * 0.66);
|
||||
|
||||
void _layoutHand(GameState s) {
|
||||
// در زمانِ اینترو/بُر زدنِ ابتدای هَند، کارتهای دست پنهاناند و پس از پایانِ
|
||||
// بُر زدن «پخش» میشوند (میآیند). در زمانِ پخشِ بقیهی کارتها مخفی نمیشوند.
|
||||
if (_introActive || _shuffling) {
|
||||
for (final c in _hand.values.toList()) {
|
||||
c.removeFromParent();
|
||||
}
|
||||
_hand.clear();
|
||||
return;
|
||||
}
|
||||
// مرتبسازی بر اساس خال و رتبه تا انتخاب برای بازیکن راحتتر باشد.
|
||||
final codes = List<String>.from(s.yourHand)..sort(compareCards);
|
||||
final n = codes.length;
|
||||
@@ -372,6 +407,15 @@ class HokmGame extends FlameGame {
|
||||
}
|
||||
|
||||
void _layoutTrick(GameState s) {
|
||||
// در زمانِ اینترو/بُر زدن/پخش، کارتهای روی میز پنهان میمانند تا با انیمیشن
|
||||
// تداخل نکنند (پس از پایانِ انیمیشن دوباره چیده میشوند).
|
||||
if (_introActive || _shuffling || _dealing) {
|
||||
for (final c in _trick.values.toList()) {
|
||||
c.removeFromParent();
|
||||
}
|
||||
_trick.clear();
|
||||
return;
|
||||
}
|
||||
final present = s.trick.map((t) => t.card).toSet();
|
||||
|
||||
// کارتهای trick که دیگر نیستند (دست جمع شد) ⇒ به سمت برنده برو و حذف شو.
|
||||
@@ -463,7 +507,10 @@ class HokmGame extends FlameGame {
|
||||
_backs.clear();
|
||||
_info.clear();
|
||||
|
||||
for (var seat = 0; seat < 4; seat++) {
|
||||
// پشتِ کارتِ حریفان در زمانِ بُر زدنِ ابتدای هَند پنهان است (انیمیشنِ بُر
|
||||
// خودش کارتها را پخش میکند)؛ پس از آن نمایش داده میشود.
|
||||
final hideBacks = _introActive || _shuffling;
|
||||
for (var seat = 0; seat < 4 && !hideBacks; seat++) {
|
||||
if (seat == s.yourSeat) continue;
|
||||
final count = seat < s.handCounts.length ? s.handCounts[seat] : 0;
|
||||
_addBacks(_rel(seat), count);
|
||||
|
||||
@@ -2,15 +2,18 @@ import 'package:flame/components.dart';
|
||||
import 'package:flame/effects.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// انیمیشنِ بُر زدن: دو دسته کارتِ پشترو در مرکز ریفل میشوند، کمی بالا/پایین
|
||||
/// میروند (بُر) و سپس به سمت چهار بازیکن پخش میشوند. مدتِ کل [totalMs] است
|
||||
/// تا صدای بُر زدن دقیقاً همزمان با پایانِ انیمیشن قطع شود.
|
||||
/// انیمیشنِ پخشِ کارت.
|
||||
/// - حالتِ بُر زدن ([dealOnly]=false): دو دسته در مرکز ریفل و سپس پخش میشوند.
|
||||
/// - حالتِ پخش ([dealOnly]=true): کارتها از مرکز به سمتِ چهار بازیکن پخش میشوند
|
||||
/// (پس از انتخابِ حکم، برای پخشِ بقیهی کارتها).
|
||||
class ShuffleAnimation extends PositionComponent {
|
||||
final Vector2 area;
|
||||
ShuffleAnimation(this.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 {
|
||||
@@ -29,24 +32,41 @@ class ShuffleAnimation extends PositionComponent {
|
||||
];
|
||||
|
||||
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 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)),
|
||||
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,
|
||||
@@ -54,15 +74,13 @@ class ShuffleAnimation extends PositionComponent {
|
||||
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));
|
||||
add(RemoveEffect(delay: (dealOnly ? dealMs : totalMs) / 1000));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user