feat: add depth to game
This commit is contained in:
@@ -56,12 +56,19 @@ class AppTheme {
|
|||||||
backgroundColor: AppColors.accent,
|
backgroundColor: AppColors.accent,
|
||||||
foregroundColor: AppColors.text,
|
foregroundColor: AppColors.text,
|
||||||
minimumSize: const Size.fromHeight(54),
|
minimumSize: const Size.fromHeight(54),
|
||||||
|
elevation: 8,
|
||||||
|
shadowColor: Colors.black,
|
||||||
textStyle: const TextStyle(
|
textStyle: const TextStyle(
|
||||||
fontFamily: fontFamily, fontSize: 18, fontWeight: FontWeight.bold),
|
fontFamily: fontFamily, fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(14),
|
borderRadius: BorderRadius.circular(14),
|
||||||
side: const BorderSide(color: AppColors.gold, width: 1.5),
|
side: const BorderSide(color: AppColors.gold, width: 1.5),
|
||||||
),
|
),
|
||||||
|
).copyWith(
|
||||||
|
// افکتِ فشار: کمی فرورفتن هنگام لمس برای حسِ عمق.
|
||||||
|
elevation: WidgetStateProperty.resolveWith(
|
||||||
|
(states) => states.contains(WidgetState.pressed) ? 2.0 : 8.0,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -106,6 +106,14 @@ class CardComponent extends PositionComponent
|
|||||||
final radius = Radius.circular(size.x * 0.09);
|
final radius = Radius.circular(size.x * 0.09);
|
||||||
final rrect = RRect.fromRectAndRadius(rect, radius);
|
final rrect = RRect.fromRectAndRadius(rect, radius);
|
||||||
|
|
||||||
|
// سایهی سبک و ارزان (بدون blurِ هر-فریمی) فقط برای کارتهای رو ⇒ عمق بدون افت کارایی.
|
||||||
|
// (drawShadow هر فریم برای دهها کارت بسیار سنگین بود و باعث لگ میشد.)
|
||||||
|
if (faceUp) {
|
||||||
|
final off = _dragging ? size.x * 0.10 : size.x * 0.03;
|
||||||
|
canvas.drawRRect(rrect.shift(Offset(off * 0.4, off)),
|
||||||
|
Paint()..color = Color(_dragging ? 0x66000000 : 0x44000000));
|
||||||
|
}
|
||||||
|
|
||||||
if (_sprite != null) {
|
if (_sprite != null) {
|
||||||
canvas.save();
|
canvas.save();
|
||||||
canvas.clipRRect(rrect);
|
canvas.clipRRect(rrect);
|
||||||
@@ -117,6 +125,22 @@ class CardComponent extends PositionComponent
|
|||||||
_drawVectorBack(canvas, rrect);
|
_drawVectorBack(canvas, rrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// براقیتِ ملایم از بالا فقط برای کارتهای رو.
|
||||||
|
if (faceUp) {
|
||||||
|
canvas.save();
|
||||||
|
canvas.clipRRect(rrect);
|
||||||
|
canvas.drawRect(
|
||||||
|
Rect.fromLTWH(0, 0, size.x, size.y * 0.5),
|
||||||
|
Paint()
|
||||||
|
..shader = const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [Color(0x2BFFFFFF), Color(0x00FFFFFF)],
|
||||||
|
).createShader(Rect.fromLTWH(0, 0, size.x, size.y * 0.5)),
|
||||||
|
);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
if (dimmed) {
|
if (dimmed) {
|
||||||
canvas.drawRRect(rrect, Paint()..color = const Color(0x73000000));
|
canvas.drawRRect(rrect, Paint()..color = const Color(0x73000000));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,24 +7,48 @@ import 'package:flutter/material.dart';
|
|||||||
const _gold = Color(0xFFE9B949);
|
const _gold = Color(0xFFE9B949);
|
||||||
const _goldDark = Color(0xFFB8860B);
|
const _goldDark = Color(0xFFB8860B);
|
||||||
|
|
||||||
/// نمدِ سبزِ بیضیشکلِ میز با حاشیهی طلایی.
|
/// نمدِ سبزِ بیضیشکلِ میز با عمق: لبهی برجسته، گرادیانِ شعاعی و وینیت.
|
||||||
class Felt extends PositionComponent with HasGameReference {
|
class Felt extends PositionComponent with HasGameReference {
|
||||||
@override
|
@override
|
||||||
void render(Canvas canvas) {
|
void render(Canvas canvas) {
|
||||||
final w = game.size.x, h = game.size.y;
|
final w = game.size.x, h = game.size.y;
|
||||||
final rect = Rect.fromCenter(
|
final center = Offset(w / 2, h / 2);
|
||||||
center: Offset(w / 2, h / 2),
|
final rect = Rect.fromCenter(center: center, width: w * 0.86, height: h * 0.62);
|
||||||
width: w * 0.86,
|
final radius = Radius.circular(h * 0.3);
|
||||||
height: h * 0.62,
|
final felt = RRect.fromRectAndRadius(rect, radius);
|
||||||
);
|
|
||||||
final rrect = RRect.fromRectAndRadius(rect, Radius.circular(h * 0.3));
|
// ۱) لبهی چوبیِ بیرونی (ریل) با گرادیان — حسِ برجستگی بدون drawShadowِ هر-فریمی.
|
||||||
canvas.drawRRect(rrect, Paint()..color = const Color(0xFF1B5E20));
|
final rail = RRect.fromRectAndRadius(
|
||||||
|
rect.inflate(w * 0.03), Radius.circular(h * 0.33));
|
||||||
canvas.drawRRect(
|
canvas.drawRRect(
|
||||||
rrect,
|
rail,
|
||||||
|
Paint()
|
||||||
|
..shader = const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [Color(0xFF5A2E12), Color(0xFF2E1608)],
|
||||||
|
).createShader(rail.outerRect),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ۲) حلقهی طلایی بین ریل و نمد.
|
||||||
|
canvas.drawRRect(
|
||||||
|
RRect.fromRectAndRadius(rect.inflate(w * 0.008), radius),
|
||||||
Paint()
|
Paint()
|
||||||
..style = PaintingStyle.stroke
|
..style = PaintingStyle.stroke
|
||||||
..strokeWidth = 6
|
..strokeWidth = w * 0.012
|
||||||
..color = _goldDark,
|
..color = _gold,
|
||||||
|
);
|
||||||
|
|
||||||
|
// ۳) نمدِ سبز با گرادیانِ شعاعی (مرکز روشن، لبهها تیره) — خودش حسِ وینیت/عمق میدهد.
|
||||||
|
canvas.drawRRect(
|
||||||
|
felt,
|
||||||
|
Paint()
|
||||||
|
..shader = RadialGradient(
|
||||||
|
center: Alignment.center,
|
||||||
|
radius: 0.95,
|
||||||
|
colors: const [Color(0xFF34A03F), Color(0xFF0E3614)],
|
||||||
|
stops: const [0.45, 1.0],
|
||||||
|
).createShader(rect),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,13 +195,59 @@ class _MenuButton extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// رنگِ تیرهترِ پایه برای بِوِل (لبهی پایینیِ برجسته).
|
||||||
|
final dark = Color.lerp(color, Colors.black, 0.45)!;
|
||||||
|
final light = Color.lerp(color, Colors.white, 0.12)!;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 280,
|
width: 280,
|
||||||
child: ElevatedButton.icon(
|
child: Material(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: color),
|
color: Colors.transparent,
|
||||||
onPressed: onTap,
|
borderRadius: BorderRadius.circular(16),
|
||||||
icon: Icon(icon, color: AppColors.gold),
|
child: InkWell(
|
||||||
label: Text(label),
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
onTap: onTap,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [light, color, dark],
|
||||||
|
stops: const [0, 0.5, 1],
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(color: AppColors.gold, width: 1.6),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.55),
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
),
|
||||||
|
// هایلایتِ بالا برای حسِ شیشهای/برجسته.
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.white.withValues(alpha: 0.12),
|
||||||
|
blurRadius: 1,
|
||||||
|
offset: const Offset(0, 1),
|
||||||
|
spreadRadius: -1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: AppColors.gold),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(label,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColors.text,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
shadows: [Shadow(color: Colors.black54, blurRadius: 3)],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user