8739fc0e26
Introduces candy-gloss tile rendering (diagonal gradient + glass highlight + optional glow) via a shared paintGlossyTile() in tile_painter.dart, applied to board filled-cells and tray/drag-overlay pieces. Adds ThemeColors to palette.dart for UI-layer season color resolution, and activeThemeProvider for one-call access to the active season's theme. Regenerates the game_screen golden to reflect the new look.
136 lines
3.8 KiB
Dart
136 lines
3.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../game/models/cell.dart';
|
|
import '../../game/models/grid.dart';
|
|
import '../../game/models/piece.dart';
|
|
import '../theme/palette.dart';
|
|
import 'board_geometry.dart';
|
|
import 'piece_painter.dart';
|
|
import 'tile_painter.dart';
|
|
|
|
/// Drag ghost preview: a piece hovering at a snapped anchor.
|
|
class GhostSpec {
|
|
const GhostSpec({
|
|
required this.piece,
|
|
required this.anchorX,
|
|
required this.anchorY,
|
|
required this.legal,
|
|
});
|
|
|
|
final Piece piece;
|
|
final int anchorX;
|
|
final int anchorY;
|
|
final bool legal;
|
|
}
|
|
|
|
class BoardPainter extends CustomPainter {
|
|
const BoardPainter({
|
|
required this.grid,
|
|
required this.ghost,
|
|
required this.flashProgress,
|
|
required this.flashRows,
|
|
required this.flashCols,
|
|
});
|
|
|
|
final GridState grid;
|
|
final GhostSpec? ghost;
|
|
|
|
/// 1.0 -> 0.0 while the clear flash fades.
|
|
final double flashProgress;
|
|
final List<int> flashRows;
|
|
final List<int> flashCols;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final geo = BoardGeometry(boardSize: size.width);
|
|
final radius = Radius.circular(geo.cellSize * 0.18);
|
|
final inset = geo.cellSize * 0.05;
|
|
|
|
final bg = Paint()..color = GamePalette.boardBackground;
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(Offset.zero & size, const Radius.circular(12)),
|
|
bg,
|
|
);
|
|
|
|
for (var y = 0; y < GridState.size; y++) {
|
|
for (var x = 0; x < GridState.size; x++) {
|
|
final rect = geo.cellRect(x, y).deflate(inset);
|
|
final cell = grid.cellAt(x, y);
|
|
switch (cell.type) {
|
|
case CellType.empty:
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(rect, radius),
|
|
Paint()..color = GamePalette.emptyCell,
|
|
);
|
|
case CellType.filled:
|
|
paintGlossyTile(canvas, rect, GamePalette.tile(cell.colorId));
|
|
case CellType.gem:
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(rect, radius),
|
|
Paint()..color = GamePalette.emptyCell,
|
|
);
|
|
_paintGem(canvas, rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
final g = ghost;
|
|
if (g != null) {
|
|
paintPiece(
|
|
canvas,
|
|
g.piece,
|
|
cellSize: geo.cellSize,
|
|
origin: Offset(g.anchorX * geo.cellSize, g.anchorY * geo.cellSize),
|
|
overrideColor:
|
|
g.legal ? GamePalette.ghostLegal : GamePalette.ghostIllegal,
|
|
);
|
|
}
|
|
|
|
if (flashProgress > 0) {
|
|
final flash = Paint()
|
|
..color = Colors.white.withValues(alpha: 0.75 * flashProgress);
|
|
for (final y in flashRows) {
|
|
canvas.drawRect(
|
|
Rect.fromLTWH(0, y * geo.cellSize, size.width, geo.cellSize),
|
|
flash,
|
|
);
|
|
}
|
|
for (final x in flashCols) {
|
|
canvas.drawRect(
|
|
Rect.fromLTWH(x * geo.cellSize, 0, geo.cellSize, size.height),
|
|
flash,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _paintGem(Canvas canvas, Rect rect) {
|
|
final glowPaint = Paint()
|
|
..color = GamePalette.gem.withValues(alpha: 0.45)
|
|
..maskFilter = MaskFilter.blur(BlurStyle.normal, rect.width * 0.25);
|
|
canvas.drawCircle(rect.center, rect.width * 0.32, glowPaint);
|
|
final center = rect.center;
|
|
final r = rect.width * 0.32;
|
|
final path = Path()
|
|
..moveTo(center.dx, center.dy - r)
|
|
..lineTo(center.dx + r, center.dy)
|
|
..lineTo(center.dx, center.dy + r)
|
|
..lineTo(center.dx - r, center.dy)
|
|
..close();
|
|
canvas.drawPath(path, Paint()..color = GamePalette.gem);
|
|
canvas.drawPath(
|
|
path,
|
|
Paint()
|
|
..color = Colors.white.withValues(alpha: 0.6)
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = rect.width * 0.05,
|
|
);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(BoardPainter old) =>
|
|
old.grid != grid ||
|
|
old.ghost != ghost ||
|
|
old.flashProgress != flashProgress;
|
|
}
|