feat: add carpet

This commit is contained in:
2026-07-03 21:56:34 +03:30
parent 5160deb973
commit 7acd72c286
21 changed files with 536 additions and 156 deletions
@@ -69,14 +69,18 @@ class HokmGame extends FlameGame {
double _hbAccum = 0; // انباشتِ زمان برای تکرارِ منظمِ ضربان تا پایانِ نوبت
bool _wasMyTurn = false;
HokmGame(this.cubit, {this.skin = 'simple'});
/// فرشِ انتخابی؛ 'classic' یعنی سطحِ میزِ ترسیمی. فرشِ تصویری به‌عنوانِ سطحِ
/// میز (بریده در شکلِ میز) روی زمینِ لاجوردی کشیده می‌شود.
final String carpet;
HokmGame(this.cubit, {this.skin = 'simple', this.carpet = 'classic'});
@override
Color backgroundColor() => AppColors.lapisNight;
@override
Future<void> onLoad() async {
add(Felt());
add(Felt(carpet: carpet));
_sub = cubit.stream.listen((ui) {
if (ui.state == null) return;
final s = ui.state!;
@@ -3,22 +3,39 @@ import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flutter/material.dart';
import '../../../../../core/network/card_images.dart';
import '../../../../../core/theme/app_theme.dart';
// رنگ‌های مشترکِ میز (منبعِ واحد در AppColors).
const _gold = AppColors.gold;
const _goldDark = AppColors.goldDark;
/// میز: زمینِ سبزِ نمدی در کلِ صفحه + یک «میزِ» مرکزیِ سرمه‌ای با قابِ طلاییِ
/// دولایه (مطابقِ تصویرِ مرجع). کارت‌های زمین داخلِ ناحیه‌ی سرمه‌ای انداخته می‌شوند
/// و پشت‌کارتِ حریفان روی نمدِ سبزِ دورِ آن می‌نشیند.
/// میز: زمینِ لاجوردیِ نمدی در کلِ صفحه + یک «میزِ» مرکزی با قابِ طلاییِ دولایه.
/// اگر فرشی انتخاب شده باشد، سطحِ میز تصویرِ فرش است (بریده‌شده در شکلِ میز)؛
/// وگرنه سطحِ سرمه‌ایِ ترسیمی. کارت‌ها داخلِ همین ناحیه انداخته می‌شوند.
class Felt extends PositionComponent with HasGameReference {
/// شناسه‌ی فرشِ انتخابی؛ 'classic' یعنی سطحِ ترسیمی (بدون تصویر).
final String carpet;
Felt({this.carpet = 'classic'});
Sprite? _carpetSprite;
bool get _hasCarpet => carpet != 'classic';
@override
Future<void> onLoad() async {
if (_hasCarpet) {
_carpetSprite = await CardImages.carpet(carpet);
}
}
@override
void render(Canvas canvas) {
final w = game.size.x, h = game.size.y;
final center = Offset(w / 2, h / 2);
// ۱) زمینِ لاجوردیِ نمدی (کلِ صفحه) با وینیتِ شعاعی برای عمق.
// ۱) زمینِ لاجوردیِ نمدی (کلِ صفحه) با وینیتِ شعاعی برای عمق. همیشه کشیده
// می‌شود تا زیرِ میز/فرش یکدست باشد و لبه‌های فرش با پس‌زمینه جور شود.
canvas.drawRect(
Rect.fromLTWH(0, 0, w, h),
Paint()
@@ -30,7 +47,7 @@ class Felt extends PositionComponent with HasGameReference {
).createShader(Rect.fromLTWH(0, 0, w, h)),
);
// ۲) میزِ مرکزیِ سرمه‌ای با قابِ طلایی.
// ۲) میزِ مرکزی با قابِ طلایی.
final rect = Rect.fromCenter(
center: center, width: w * 0.72, height: h * 0.46);
final radius = Radius.circular(h * 0.05);
@@ -55,17 +72,32 @@ class Felt extends PositionComponent with HasGameReference {
).createShader(rect),
);
// سطحِ سرمه‌ایِ میز با گرادیانِ شعاعی (مرکز روشن‌تر).
canvas.drawRRect(
table,
Paint()
..shader = RadialGradient(
center: Alignment.center,
radius: 0.9,
colors: const [AppColors.lapisLo, AppColors.lapisInk],
stops: const [0.4, 1.0],
).createShader(rect),
);
// سطحِ میز: تصویرِ فرش (بریده در شکلِ میز) یا سطحِ سرمه‌ایِ ترسیمی.
final sprite = _carpetSprite;
if (_hasCarpet && sprite != null) {
canvas.save();
canvas.clipRRect(table);
// فرش را به‌صورتِ cover داخلِ مستطیلِ میز می‌کشیم.
sprite.render(
canvas,
position: Vector2(rect.left, rect.top),
size: Vector2(rect.width, rect.height),
);
// تیره‌ترِ ملایم برای خوانایی کارت‌ها روی فرش.
canvas.drawRRect(table, Paint()..color = const Color(0x1A000000));
canvas.restore();
} else {
canvas.drawRRect(
table,
Paint()
..shader = RadialGradient(
center: Alignment.center,
radius: 0.9,
colors: const [AppColors.lapisLo, AppColors.lapisInk],
stops: const [0.4, 1.0],
).createShader(rect),
);
}
// خطِ طلاییِ نازکِ داخلی (قابِ دولایه).
canvas.drawRRect(