init
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:flame/events.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// نسبت ابعاد کارت (۵۰۰×۷۲۶ منبع).
|
||||
const double kCardRatio = 726 / 500;
|
||||
|
||||
/// یک کارت روی میز؛ اگر تصویر `assets/images/cards/<code>.png` موجود باشد از آن
|
||||
/// استفاده میکند، وگرنه نسخهی برداری میکشد. برای پشت کارت `back.jpg`.
|
||||
class CardComponent extends PositionComponent with TapCallbacks, HasGameReference {
|
||||
final String code; // مثل "AS"؛ برای پشت کارت خالی
|
||||
final bool faceUp;
|
||||
VoidCallback? onTap; // با تغییر نوبت/مجازبودن بهروز میشود
|
||||
bool dimmed; // کارت غیرمجاز/غیرفعال
|
||||
Sprite? _sprite;
|
||||
|
||||
CardComponent({
|
||||
required this.code,
|
||||
required this.faceUp,
|
||||
this.onTap,
|
||||
this.dimmed = false,
|
||||
super.position,
|
||||
super.size,
|
||||
super.angle,
|
||||
super.priority,
|
||||
super.anchor = Anchor.center,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
try {
|
||||
_sprite = await game.loadSprite(faceUp ? 'cards/$code.png' : 'cards/back.jpg');
|
||||
} catch (_) {
|
||||
_sprite = null; // fallback برداری
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onTapDown(TapDownEvent event) {
|
||||
if (onTap != null && !dimmed) onTap!.call();
|
||||
}
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
final rect = size.toRect();
|
||||
final radius = Radius.circular(size.x * 0.09);
|
||||
final rrect = RRect.fromRectAndRadius(rect, radius);
|
||||
|
||||
if (_sprite != null) {
|
||||
canvas.save();
|
||||
canvas.clipRRect(rrect);
|
||||
_sprite!.render(canvas, size: size);
|
||||
canvas.restore();
|
||||
} else if (faceUp) {
|
||||
_drawVectorFace(canvas, rrect);
|
||||
} else {
|
||||
_drawVectorBack(canvas, rrect);
|
||||
}
|
||||
|
||||
if (dimmed) {
|
||||
canvas.drawRRect(rrect, Paint()..color = const Color(0x73000000));
|
||||
}
|
||||
canvas.drawRRect(
|
||||
rrect,
|
||||
Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1.5
|
||||
..color = const Color(0xFF1A1A1A),
|
||||
);
|
||||
}
|
||||
|
||||
void _drawVectorBack(Canvas canvas, RRect rrect) {
|
||||
canvas.drawRRect(rrect, Paint()..color = const Color(0xFF1C3A66));
|
||||
final inner = rrect.deflate(size.x * 0.08);
|
||||
canvas.drawRRect(
|
||||
inner,
|
||||
Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 2
|
||||
..color = const Color(0xFFE9B949),
|
||||
);
|
||||
}
|
||||
|
||||
void _drawVectorFace(Canvas canvas, RRect rrect) {
|
||||
canvas.drawRRect(rrect, Paint()..color = Colors.white);
|
||||
final rank = code.substring(0, code.length - 1);
|
||||
final suit = code.substring(code.length - 1);
|
||||
final (symbol, color) = _suit(suit);
|
||||
|
||||
_text(canvas, '$rank$symbol', size.x * 0.26, color,
|
||||
Offset(size.x * 0.08, size.y * 0.05));
|
||||
// نماد بزرگ وسط
|
||||
_text(canvas, symbol, size.x * 0.5, color,
|
||||
Offset(size.x * 0.5, size.y * 0.5), center: true);
|
||||
}
|
||||
|
||||
(String, Color) _suit(String s) {
|
||||
switch (s) {
|
||||
case 'H':
|
||||
return ('♥', const Color(0xFFD32F2F));
|
||||
case 'D':
|
||||
return ('♦', const Color(0xFFD32F2F));
|
||||
case 'C':
|
||||
return ('♣', const Color(0xFF1A1A1A));
|
||||
default:
|
||||
return ('♠', const Color(0xFF1A1A1A));
|
||||
}
|
||||
}
|
||||
|
||||
void _text(Canvas canvas, String s, double fontSize, Color color, Offset at,
|
||||
{bool center = false}) {
|
||||
final tp = TextPainter(
|
||||
text: TextSpan(
|
||||
text: s, style: TextStyle(color: color, fontSize: fontSize)),
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout();
|
||||
final offset = center ? at - Offset(tp.width / 2, tp.height / 2) : at;
|
||||
tp.paint(canvas, offset);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user