feat: better ux
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:flame/effects.dart';
|
||||
import 'package:flame/events.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -7,17 +8,23 @@ const double kCardRatio = 726 / 500;
|
||||
|
||||
/// یک کارت روی میز؛ اگر تصویر `assets/images/cards/<code>.png` موجود باشد از آن
|
||||
/// استفاده میکند، وگرنه نسخهی برداری میکشد. برای پشت کارت `back.jpg`.
|
||||
class CardComponent extends PositionComponent with TapCallbacks, HasGameReference {
|
||||
/// کارتهای قابلبازی هم با tap و هم با کشیدن (drag) به سمت زمین بازی میشوند.
|
||||
class CardComponent extends PositionComponent
|
||||
with TapCallbacks, DragCallbacks, HasGameReference {
|
||||
final String code; // مثل "AS"؛ برای پشت کارت خالی
|
||||
final bool faceUp;
|
||||
VoidCallback? onTap; // با تغییر نوبت/مجازبودن بهروز میشود
|
||||
VoidCallback? onPlay; // در صورت مجاز بودن، بازیِ این کارت
|
||||
bool dimmed; // کارت غیرمجاز/غیرفعال
|
||||
Vector2? home; // موقعیت اصلی در دست (برای برگشت پس از کشیدنِ ناقص)
|
||||
Rect? dropZone; // ناحیهی وسط میز؛ رهاکردن کارت در آن یعنی بازی
|
||||
Sprite? _sprite;
|
||||
bool _dragging = false;
|
||||
bool _overZone = false; // کارت روی ناحیهی انداختن است (برای هایلایت)
|
||||
|
||||
CardComponent({
|
||||
required this.code,
|
||||
required this.faceUp,
|
||||
this.onTap,
|
||||
this.onPlay,
|
||||
this.dimmed = false,
|
||||
super.position,
|
||||
super.size,
|
||||
@@ -26,6 +33,8 @@ class CardComponent extends PositionComponent with TapCallbacks, HasGameReferenc
|
||||
super.anchor = Anchor.center,
|
||||
});
|
||||
|
||||
bool get _playable => onPlay != null && !dimmed;
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
try {
|
||||
@@ -36,8 +45,60 @@ class CardComponent extends PositionComponent with TapCallbacks, HasGameReferenc
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownEvent event) {
|
||||
if (onTap != null && !dimmed) onTap!.call();
|
||||
void onTapUp(TapUpEvent event) {
|
||||
if (_playable) onPlay!.call();
|
||||
}
|
||||
|
||||
@override
|
||||
void onDragStart(DragStartEvent event) {
|
||||
super.onDragStart(event);
|
||||
if (!_playable) return;
|
||||
_dragging = true;
|
||||
priority = 1000; // روی همهی کارتها
|
||||
scale = Vector2.all(1.12); // بزرگنمایی هنگام کشیدن (فیدبک)
|
||||
}
|
||||
|
||||
@override
|
||||
void onDragUpdate(DragUpdateEvent event) {
|
||||
if (!_dragging) return;
|
||||
position += event.localDelta;
|
||||
_overZone = _inDropZone();
|
||||
}
|
||||
|
||||
@override
|
||||
void onDragEnd(DragEndEvent event) {
|
||||
super.onDragEnd(event);
|
||||
if (!_dragging) return;
|
||||
_dragging = false;
|
||||
scale = Vector2.all(1);
|
||||
// فقط اگر داخل ناحیهی وسط میز رها شد ⇒ بازی؛ وگرنه برگشت به جای مرتبِ خود.
|
||||
if (_inDropZone()) {
|
||||
onPlay?.call();
|
||||
} else {
|
||||
_returnHome();
|
||||
}
|
||||
_overZone = false;
|
||||
}
|
||||
|
||||
@override
|
||||
void onDragCancel(DragCancelEvent event) {
|
||||
super.onDragCancel(event);
|
||||
if (!_dragging) return;
|
||||
_dragging = false;
|
||||
_overZone = false;
|
||||
scale = Vector2.all(1);
|
||||
_returnHome();
|
||||
}
|
||||
|
||||
bool _inDropZone() {
|
||||
final z = dropZone;
|
||||
if (z != null) return z.contains(position.toOffset());
|
||||
return position.y < game.size.y * 0.72; // fallback
|
||||
}
|
||||
|
||||
void _returnHome() {
|
||||
if (home == null) return;
|
||||
add(MoveToEffect(home!, EffectController(duration: 0.2, curve: Curves.easeOut)));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -67,6 +128,18 @@ class CardComponent extends PositionComponent with TapCallbacks, HasGameReferenc
|
||||
..strokeWidth = 1.5
|
||||
..color = const Color(0xFF1A1A1A),
|
||||
);
|
||||
|
||||
// هایلایت طلایی وقتی کارت روی ناحیهی انداختن است (رهاکنی، بازی میشود).
|
||||
if (_dragging && _overZone) {
|
||||
canvas.drawRRect(
|
||||
rrect,
|
||||
Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = size.x * 0.06
|
||||
..color = const Color(0xFFE9B949)
|
||||
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 6),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _drawVectorBack(Canvas canvas, RRect rrect) {
|
||||
|
||||
Reference in New Issue
Block a user