feat: add characters
This commit is contained in:
@@ -9,7 +9,9 @@ class LobbyPlayer {
|
||||
final String avatar; // seed آواتارِ انتخابیِ کاربر
|
||||
final bool host;
|
||||
final int seat; // جایگاهِ مطلق (۰..۳)
|
||||
const LobbyPlayer(this.name, this.avatar, this.host, this.seat);
|
||||
final String avatarImg; // شخصیتِ آواتارِ انتخابی (<id>.<ext>؛ خالی ⇒ تصادفی)
|
||||
const LobbyPlayer(this.name, this.avatar, this.host, this.seat,
|
||||
{this.avatarImg = ''});
|
||||
|
||||
/// seedِ آواتار برای نمایش: آواتارِ انتخابی، وگرنه نام.
|
||||
String get avatarSeed => avatar.isNotEmpty ? avatar : name;
|
||||
@@ -42,6 +44,7 @@ class TableLobby {
|
||||
(e['avatar'] ?? '') as String,
|
||||
(e['host'] ?? false) as bool,
|
||||
(e['seat'] ?? 0) as int,
|
||||
avatarImg: (e['avatar_img'] ?? '') as String,
|
||||
))
|
||||
.toList(),
|
||||
isHost: (j['host'] ?? false) as bool,
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../../../../core/locator/locator.dart';
|
||||
import '../../../../core/network/ws_client.dart';
|
||||
import '../../../../core/service/app_sounds.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../core/widgets/player_avatar.dart';
|
||||
import '../../../shop/data/data_source/remote/frame_api_provider.dart';
|
||||
import '../../../tournament/data/data_source/remote/tournament_api_provider.dart';
|
||||
import '../../../tournament/domain/entities/tournament.dart';
|
||||
@@ -39,7 +40,6 @@ class GameScreen extends StatefulWidget {
|
||||
|
||||
class _GameScreenState extends State<GameScreen> {
|
||||
late final HokmGame _game;
|
||||
String _carpet = 'classic'; // فرشِ انتخابی (برای پسزمینهی پشتِ صحنه)
|
||||
Timer? _introTimer;
|
||||
bool _introHidden = false;
|
||||
int _countdown = 0; // شمارشِ معکوسِ شروعِ بازی پس از یافتنِ حریفان (۳…۲…۱)
|
||||
@@ -50,11 +50,12 @@ class _GameScreenState extends State<GameScreen> {
|
||||
super.initState();
|
||||
final ws = context.read<WalletBloc>().state.walletStatus;
|
||||
final skin = ws is WalletLoaded ? ws.wallet.selectedCard : 'simple';
|
||||
_carpet = ws is WalletLoaded ? ws.wallet.selectedCarpet : 'classic';
|
||||
// URL کاملِ فرش از سرور میآید (خالی ⇒ میزِ کلاسیک).
|
||||
final carpetUrl = ws is WalletLoaded ? ws.wallet.selectedCarpetImg : '';
|
||||
_game = HokmGame(
|
||||
context.read<GameBloc>(),
|
||||
skin: skin.isEmpty ? 'simple' : skin,
|
||||
carpet: _carpet.isEmpty ? 'classic' : _carpet,
|
||||
carpetUrl: carpetUrl,
|
||||
);
|
||||
_loadTournament();
|
||||
locator<FrameApiProvider>().warmCache(); // رنگِ قابها برای HUD (best-effort)
|
||||
|
||||
@@ -253,7 +253,10 @@ class _SearchSlot extends StatelessWidget {
|
||||
)
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: RandomAvatar(p.avatarSeed),
|
||||
child: PlayerAvatar(
|
||||
seed: p.avatarSeed,
|
||||
imageUrl: p.avatarImg,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:random_avatar/random_avatar.dart';
|
||||
|
||||
import '../../../../core/network/ws_client.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
import '../../../../core/widgets/game_ui.dart';
|
||||
import '../../../../core/widgets/player_avatar.dart';
|
||||
import '../bloc/game_bloc.dart';
|
||||
import '../bloc/game_state.dart';
|
||||
import 'game_screen.dart';
|
||||
|
||||
@@ -253,7 +253,10 @@ class _LobbyViewState extends State<_LobbyView> {
|
||||
)
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(9),
|
||||
child: RandomAvatar(p.avatarSeed),
|
||||
child: PlayerAvatar(
|
||||
seed: p.avatarSeed,
|
||||
imageUrl: p.avatarImg,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!empty)
|
||||
|
||||
@@ -68,18 +68,18 @@ class HokmGame extends FlameGame {
|
||||
// ضربانِ قلبِ نوبتِ کاربر (منطق در TurnHeartbeat جدا شده است).
|
||||
final TurnHeartbeat _heart = TurnHeartbeat();
|
||||
|
||||
/// فرشِ انتخابی؛ 'classic' یعنی سطحِ میزِ ترسیمی. فرشِ تصویری بهعنوانِ سطحِ
|
||||
/// میز (بریده در شکلِ میز) روی زمینِ لاجوردی کشیده میشود.
|
||||
final String carpet;
|
||||
/// URL کاملِ تصویرِ فرش (از سرور)؛ خالی یعنی میزِ ترسیمیِ کلاسیک. فرشِ تصویری
|
||||
/// بهعنوانِ سطحِ میز (بریده در شکلِ میز) روی زمینِ لاجوردی کشیده میشود.
|
||||
final String carpetUrl;
|
||||
|
||||
HokmGame(this.cubit, {this.skin = 'simple', this.carpet = 'classic'});
|
||||
HokmGame(this.cubit, {this.skin = 'simple', this.carpetUrl = ''});
|
||||
|
||||
@override
|
||||
Color backgroundColor() => AppColors.lapisNight;
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
add(Felt(carpet: carpet));
|
||||
add(Felt(carpetUrl: carpetUrl));
|
||||
if (!AppSettings.I.lowGraphics.value) {
|
||||
add(Motes()); // ذراتِ طلاییِ معلق برای اتمسفر (در حالتِ کممصرف خاموش)
|
||||
}
|
||||
|
||||
@@ -16,19 +16,19 @@ const _goldDark = AppColors.goldDark;
|
||||
/// اگر فرشی انتخاب شده باشد، سطحِ میز تصویرِ فرش است (بریدهشده در شکلِ میز)؛
|
||||
/// وگرنه سطحِ سرمهایِ ترسیمی. کارتها داخلِ همین ناحیه انداخته میشوند.
|
||||
class Felt extends PositionComponent with HasGameReference {
|
||||
/// شناسهی فرشِ انتخابی؛ 'classic' یعنی سطحِ ترسیمی (بدون تصویر).
|
||||
final String carpet;
|
||||
Felt({this.carpet = 'classic'});
|
||||
/// URL کاملِ تصویرِ فرش (از سرور)؛ خالی یعنی سطحِ ترسیمیِ کلاسیک (بدون تصویر).
|
||||
final String carpetUrl;
|
||||
Felt({this.carpetUrl = ''});
|
||||
|
||||
Sprite? _carpetSprite;
|
||||
Sprite? _bgSprite; // پسزمینهی نقاشیشده (اختیاری، قابلِ تعویض)
|
||||
|
||||
bool get _hasCarpet => carpet != 'classic';
|
||||
bool get _hasCarpet => carpetUrl.isNotEmpty;
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
if (_hasCarpet) {
|
||||
_carpetSprite = await CardImages.carpet(carpet);
|
||||
_carpetSprite = await CardImages.carpetByUrl(carpetUrl);
|
||||
}
|
||||
// پسزمینهی سفارشی (تالار/کاخ): فایلِ assets/images/game_bg.jpg را بگذارید.
|
||||
// اگر نبود یا حالتِ کممصرف باشد، به گرادیانِ لاجوردیِ پیشفرض برمیگردد.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
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 '../../../../core/theme/ranks.dart';
|
||||
import '../../../../core/widgets/player_avatar.dart';
|
||||
import '../../domain/entities/game_entities.dart';
|
||||
import '../bloc/game_state.dart';
|
||||
|
||||
|
||||
@@ -91,8 +91,12 @@ class _PlayerSeat extends StatelessWidget {
|
||||
color: Colors.white70,
|
||||
size: diameter * 0.5,
|
||||
)
|
||||
: RandomAvatar(
|
||||
player.avatarSeed.isEmpty ? '?' : player.avatarSeed),
|
||||
: PlayerAvatar(
|
||||
seed: player.avatarSeed.isEmpty
|
||||
? '?'
|
||||
: player.avatarSeed,
|
||||
imageUrl: player.avatarImg,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user