feat: better ux
This commit is contained in:
@@ -25,9 +25,9 @@ class HokmGame extends FlameGame {
|
||||
double _cardW = 60;
|
||||
double _cardH = 87;
|
||||
|
||||
double _shake = 0; // شدت تکانِ صفحه (افکت برد با حکم)
|
||||
double _shake = 0; // شدت تکانِ صفحه (افکت بریدن با حکم)
|
||||
double _t = 0; // زمان برای نوسان تکان
|
||||
bool _prevTrickDone = false;
|
||||
List<String> _prevTrick = const []; // کدِ کارتهای دست جاری (برای تشخیص کارت تازهبازیشده)
|
||||
|
||||
HokmGame(this.cubit);
|
||||
|
||||
@@ -40,18 +40,44 @@ class HokmGame extends FlameGame {
|
||||
_sub = cubit.stream.listen((ui) {
|
||||
if (ui.state != null) {
|
||||
final s = ui.state!;
|
||||
if (s.trickDone && !_prevTrickDone) _onTrickComplete(s);
|
||||
_prevTrickDone = s.trickDone;
|
||||
_checkCut(s);
|
||||
_s = s;
|
||||
_relayout();
|
||||
}
|
||||
});
|
||||
if (cubit.state.state != null) {
|
||||
_prevTrick = cubit.state.state!.trick.map((t) => t.card).toList();
|
||||
_s = cubit.state.state;
|
||||
_relayout();
|
||||
}
|
||||
}
|
||||
|
||||
// اگر دقیقاً یک کارت تازه به زمین اضافه شده و آن کارت «بُرِش با حکم» باشد
|
||||
// (خالِ زمینه آتو نیست ولی کارتِ تازه آتوست)، همان لحظه تکان + رعد.
|
||||
void _checkCut(GameState s) {
|
||||
final now = s.trick.map((t) => t.card).toList();
|
||||
final added = now.length == _prevTrick.length + 1 &&
|
||||
_isPrefix(_prevTrick, now);
|
||||
if (added) {
|
||||
final last = now.last;
|
||||
if (s.trump != null &&
|
||||
s.leadSuit != null &&
|
||||
s.leadSuit != s.trump &&
|
||||
_suitName(last) == s.trump) {
|
||||
_shake = 1.0;
|
||||
add(_Lightning());
|
||||
}
|
||||
}
|
||||
_prevTrick = now;
|
||||
}
|
||||
|
||||
static bool _isPrefix(List<String> a, List<String> b) {
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (a[i] != b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void update(double dt) {
|
||||
super.update(dt);
|
||||
@@ -73,37 +99,6 @@ class HokmGame extends FlameGame {
|
||||
}
|
||||
}
|
||||
|
||||
// هنگام کاملشدن یک دست: اگر برنده «بریده» باشد (خالِ زمینه آتو نبوده ولی
|
||||
// کارتِ برنده آتوست — یعنی بازیکن چون خال زمینه را نداشت آتو زد) تکان + رعد.
|
||||
void _onTrickComplete(GameState s) {
|
||||
if (s.trick.length < 4) return;
|
||||
final winner = _winnerCard(s);
|
||||
final cutWithTrump = s.trump != null &&
|
||||
s.leadSuit != s.trump &&
|
||||
_suitName(winner.card) == s.trump;
|
||||
_shake = cutWithTrump ? 1.0 : 0.3;
|
||||
if (cutWithTrump) add(_Lightning());
|
||||
}
|
||||
|
||||
TrickCard _winnerCard(GameState s) {
|
||||
var best = s.trick.first;
|
||||
for (final tc in s.trick.skip(1)) {
|
||||
if (_beats(tc.card, best.card, s.trump, s.leadSuit)) best = tc;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
// آیا کارت a کارت b را میبرد (با توجه به حکم و خال زمینه)؟ مطابق منطق سرور.
|
||||
bool _beats(String a, String b, String? trump, String? lead) {
|
||||
final aT = _suitName(a) == trump, bT = _suitName(b) == trump;
|
||||
if (aT && !bT) return true;
|
||||
if (!aT && bT) return false;
|
||||
if (aT && bT) return _rankValue(a) > _rankValue(b);
|
||||
if (_suitName(a) != lead) return false;
|
||||
if (_suitName(b) != lead) return true;
|
||||
return _rankValue(a) > _rankValue(b);
|
||||
}
|
||||
|
||||
@override
|
||||
void onGameResize(Vector2 size) {
|
||||
super.onGameResize(size);
|
||||
@@ -187,6 +182,14 @@ class HokmGame extends FlameGame {
|
||||
return _rankValue(a) - _rankValue(b);
|
||||
}
|
||||
|
||||
// ناحیهی وسط میز که رهاکردن کارت در آن یعنی بازی (بالاتر از دستِ شما).
|
||||
Rect _dropZone() => Rect.fromLTRB(
|
||||
size.x * 0.15,
|
||||
size.y * 0.22,
|
||||
size.x * 0.85,
|
||||
size.y * 0.66,
|
||||
);
|
||||
|
||||
void _layoutHand(GameState s) {
|
||||
// کارتهای دست بر اساس خال و سپس رتبه مرتب میشوند تا کار بازیکن راحتتر باشد.
|
||||
final codes = List<String>.from(s.yourHand)..sort(_cardCompare);
|
||||
@@ -200,10 +203,13 @@ class HokmGame extends FlameGame {
|
||||
}
|
||||
}
|
||||
|
||||
final handW = size.x * 0.72;
|
||||
final step = n > 1 ? (handW - _cardW) / (n - 1) : 0.0;
|
||||
// کارتهای دستِ خودتان بزرگتر از کارتهای روی میز.
|
||||
final hw = size.x * 0.225;
|
||||
final hh = hw * kCardRatio;
|
||||
final handW = size.x * 0.80;
|
||||
final step = n > 1 ? (handW - hw) / (n - 1) : 0.0;
|
||||
final startX = size.x / 2 - (step * (n - 1)) / 2;
|
||||
final y = size.y * 0.84;
|
||||
final y = size.y * 0.85;
|
||||
|
||||
for (var i = 0; i < n; i++) {
|
||||
final code = codes[i];
|
||||
@@ -216,16 +222,18 @@ class HokmGame extends FlameGame {
|
||||
c = CardComponent(
|
||||
code: code,
|
||||
faceUp: true,
|
||||
size: Vector2(_cardW, _cardH),
|
||||
size: Vector2(hw, hh),
|
||||
position: size / 2,
|
||||
);
|
||||
_hand[code] = c;
|
||||
add(c);
|
||||
} else {
|
||||
c.size = Vector2(_cardW, _cardH);
|
||||
c.size = Vector2(hw, hh);
|
||||
}
|
||||
c.onTap = legal ? () => cubit.playCard(code) : null;
|
||||
c.onPlay = legal ? () => cubit.playCard(code) : null;
|
||||
c.dimmed = dim;
|
||||
c.home = target;
|
||||
c.dropZone = _dropZone();
|
||||
c.priority = 10 + i;
|
||||
_moveTo(c, target);
|
||||
}
|
||||
@@ -255,8 +263,9 @@ class HokmGame extends FlameGame {
|
||||
// اگر خودِ شما بازی کردید، همان کارتِ دست را منتقل کن (پرواز به وسط).
|
||||
c = _hand.remove(tc.card);
|
||||
if (c != null) {
|
||||
c.onTap = null;
|
||||
c.onPlay = null;
|
||||
c.dimmed = false;
|
||||
c.home = null;
|
||||
} else {
|
||||
c = CardComponent(
|
||||
code: tc.card,
|
||||
@@ -333,9 +342,10 @@ class HokmGame extends FlameGame {
|
||||
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.30, size.y * 0.60)
|
||||
: Vector2(size.x * 0.70, size.y * 0.40);
|
||||
? 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);
|
||||
@@ -377,9 +387,10 @@ class HokmGame extends FlameGame {
|
||||
for (var team = 0; team < 2; team++) {
|
||||
final score = team < s.scores.length ? s.scores[team] : 0;
|
||||
final mine = team == s.yourSeat % 2;
|
||||
// یکی جلوی شما (پایین)، دیگری جلوی حریفِ سمت راست — نه جلوی یارِ بالا.
|
||||
final pos = mine
|
||||
? Vector2(size.x / 2, size.y * 0.72) // تیم شما: پایینِ مرکز
|
||||
: Vector2(size.x / 2, size.y * 0.28); // تیم حریف: بالای مرکز
|
||||
? Vector2(size.x * 0.50, size.y * 0.74)
|
||||
: Vector2(size.x * 0.84, size.y * 0.44);
|
||||
final puck = _Puck(score, radius: radius, position: pos)..priority = 22;
|
||||
_info.add(puck);
|
||||
add(puck);
|
||||
|
||||
Reference in New Issue
Block a user