feat:add frames
This commit is contained in:
@@ -8,6 +8,7 @@ class GamePlayer {
|
||||
final int coins;
|
||||
final String rankTier; // bronze..king (خالی برای بات)
|
||||
final String avatar; // seed آواتارِ انتخابیِ کاربر (خالی برای بات)
|
||||
final String frame; // قابِ آواتارِ انتخابی (کازمتیک؛ خالی ⇒ قابِ رتبه)
|
||||
|
||||
GamePlayer.fromJson(Map<String, dynamic> j)
|
||||
: seat = (j['seat'] ?? 0) as int,
|
||||
@@ -16,7 +17,8 @@ class GamePlayer {
|
||||
connected = (j['connected'] ?? false) as bool,
|
||||
coins = (j['coins'] ?? 0) as int,
|
||||
rankTier = (j['rank_tier'] ?? '') as String,
|
||||
avatar = (j['avatar'] ?? '') as String;
|
||||
avatar = (j['avatar'] ?? '') as String,
|
||||
frame = (j['frame'] ?? '') as String;
|
||||
|
||||
/// seedِ آواتار برای نمایش: آواتارِ انتخابی، وگرنه نام (fallback برای بات).
|
||||
String get avatarSeed => avatar.isNotEmpty ? avatar : name;
|
||||
|
||||
@@ -431,22 +431,28 @@ class HokmGame extends FlameGame {
|
||||
}
|
||||
}
|
||||
|
||||
// چیدمانِ بادبزنیِ منحنی: کارتها چرخش و قوسِ ملایم دارند (مثل دستِ واقعی).
|
||||
// اندازهی دست کمی بزرگتر از کارتهای روی میز است (خوانا ولی نه نامتوازن).
|
||||
// چیدمانِ بادبزنیِ واقعی: کارتها روی قوسِ یک دایره چیده و همراستا با شعاعِ آن
|
||||
// چرخانده میشوند (کارتِ وسط بالا و صاف، کناریها پایینتر و چرخیده) — مثلِ دستِ
|
||||
// واقعی. مرکزِ قوس پایینِ دست است. اندازهی دست کمی بزرگتر از کارتهای میز.
|
||||
final hw = size.x * 0.24, hh = hw * kCardRatio;
|
||||
final handW = size.x * 0.90;
|
||||
final stepX = n > 1 ? ((handW - hw) / (n - 1)).clamp(0.0, hw * 0.62) : 0.0;
|
||||
final cx = size.x / 2;
|
||||
final baseY = size.y * 0.83;
|
||||
final baseY = size.y * 0.86;
|
||||
final tMax = (n - 1) / 2;
|
||||
const edgeAngle = 0.34; // چرخشِ کارتهای کناری (رادیان)
|
||||
final dip = hh * 0.16; // افتِ عمودیِ کارتهای کناری برای قوس
|
||||
// زاویهی بینِ کارتها؛ با تعدادِ زیاد جمعتر میشود تا بادبزن بیشازحد باز نشود.
|
||||
final perCard = n > 1 ? (0.9 / (n - 1)).clamp(0.0, 0.11) : 0.0;
|
||||
final maxA = perCard * tMax;
|
||||
// شعاعِ قوس از عرضِ گسترشِ دست مشتق میشود تا فاصلهها متوازن بماند.
|
||||
final spreadX = size.x * 0.86 - hw;
|
||||
final radius = maxA > 0.01 ? (spreadX / 2) / math.sin(maxA) : size.y;
|
||||
final pivotY = baseY + radius;
|
||||
|
||||
for (var i = 0; i < n; i++) {
|
||||
final code = codes[i];
|
||||
final t = i - tMax;
|
||||
final norm = tMax > 0 ? t / tMax : 0.0;
|
||||
final target = Vector2(cx + t * stepX, baseY + norm * norm * dip);
|
||||
final a = (i - tMax) * perCard; // زاویهی این کارت روی قوس
|
||||
final target = Vector2(
|
||||
cx + radius * math.sin(a),
|
||||
pivotY - radius * math.cos(a),
|
||||
);
|
||||
final legal = _legal(code);
|
||||
var c = _hand[code];
|
||||
final isNew = c == null;
|
||||
@@ -464,7 +470,7 @@ class HokmGame extends FlameGame {
|
||||
} else {
|
||||
c.size = Vector2(hw, hh);
|
||||
}
|
||||
c.angle = norm * edgeAngle; // چرخشِ بادبزنی
|
||||
c.angle = a; // چرخشِ کارت همراستا با شعاعِ قوس
|
||||
c.onPlay = legal ? () => cubit.playCard(code) : null;
|
||||
c.dimmed = s.phase == 'playing' && s.isMyTurn && !legal;
|
||||
c.home = target;
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:random_avatar/random_avatar.dart';
|
||||
|
||||
import '../../../../core/network/ws_client.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../core/theme/frames.dart';
|
||||
import '../../domain/entities/game_entities.dart';
|
||||
import '../bloc/game_state.dart';
|
||||
|
||||
@@ -227,6 +228,10 @@ List<Color> _rankFrame(String tier) {
|
||||
}
|
||||
}
|
||||
|
||||
/// قابِ نمایشِ آواتارِ یک بازیکن: قابِ اختصاصیِ خریداریشده (اگر باشد)، وگرنه قابِ رتبه.
|
||||
List<Color> _seatFrame(GamePlayer p) =>
|
||||
frameGradient(p.frame) ?? _rankFrame(p.bot ? '' : p.rankTier);
|
||||
|
||||
class _PlayerSeat extends StatelessWidget {
|
||||
final GamePlayer player;
|
||||
final double diameter;
|
||||
@@ -287,7 +292,7 @@ class _PlayerSeat extends StatelessWidget {
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// قابِ رتبهای + آواتار (رنگِ قاب بر اساسِ نشانِ رتبهی بازیکن).
|
||||
// قابِ آواتار: قابِ اختصاصیِ خریداریشده (اگر باشد)، وگرنه قابِ رتبه.
|
||||
Container(
|
||||
width: diameter,
|
||||
height: diameter,
|
||||
@@ -296,14 +301,13 @@ class _PlayerSeat extends StatelessWidget {
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: _rankFrame(player.bot ? '' : player.rankTier),
|
||||
colors: _seatFrame(player),
|
||||
),
|
||||
boxShadow: [
|
||||
const BoxShadow(color: Colors.black54, blurRadius: 6),
|
||||
if (isTurn)
|
||||
BoxShadow(
|
||||
color: _rankFrame(player.rankTier)[0]
|
||||
.withValues(alpha: 0.6),
|
||||
color: _seatFrame(player)[0].withValues(alpha: 0.6),
|
||||
blurRadius: 12),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user