import 'package:flutter/cupertino.dart'; import 'package:gobang/models/position.dart'; import 'package:gobang/utils/constants.dart'; /// 棋盘 + 棋子绘制;最后一手支持缩放入场与高亮光圈。 class BoardPainter extends CustomPainter { BoardPainter({ required this.pieces, required this.version, this.lastMoveScale = 1, this.lastMovePulse = 0, }); final List pieces; final int version; final double lastMoveScale; final double lastMovePulse; @override void paint(Canvas canvas, Size size) { final cell = size.width / (kBoardSize - 1); final bg = Paint() ..isAntiAlias = true ..style = PaintingStyle.fill ..color = const Color(0x77cdb175); canvas.drawRect(Offset.zero & size, bg); final line = Paint() ..style = PaintingStyle.stroke ..color = CupertinoColors.systemGrey6 ..strokeWidth = 1; for (var i = 0; i < kBoardSize; i++) { final o = cell * i; canvas.drawLine(Offset(0, o), Offset(size.width, o), line); canvas.drawLine(Offset(o, 0), Offset(o, size.height), line); } final radius = cell / 2 - 2; final fill = Paint()..style = PaintingStyle.fill; final lastIndex = pieces.length - 1; for (var i = 0; i < pieces.length; i++) { final p = pieces[i]; final isLast = i == lastIndex; final center = Offset(p.dx, p.dy); final scale = isLast ? lastMoveScale.clamp(0.0, 1.2) : 1.0; final r = radius * scale; if (isLast && lastMovePulse > 0) { final ring = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 2.5 ..color = const Color(0xE0E53935).withValues( alpha: 0.85 * lastMovePulse, ); canvas.drawCircle(center, radius * (1.15 + 0.45 * lastMovePulse), ring); } fill.color = p.chess.color; if (p.chessShape.shape == 1) { canvas.drawCircle(center, r, fill); } else { canvas.drawRect( Rect.fromCircle(center: center, radius: r), fill, ); } // 最后一手中心小三角标记,方便辨认落点 if (isLast && scale > 0.85) { final mark = Paint() ..style = PaintingStyle.fill ..color = const Color(0xFFE53935); final s = radius * 0.28; final path = Path() ..moveTo(center.dx, center.dy - s) ..lineTo(center.dx - s * 0.9, center.dy + s * 0.7) ..lineTo(center.dx + s * 0.9, center.dy + s * 0.7) ..close(); canvas.drawPath(path, mark); } } } @override bool shouldRepaint(covariant BoardPainter oldDelegate) { return oldDelegate.version != version || oldDelegate.lastMoveScale != lastMoveScale || oldDelegate.lastMovePulse != lastMovePulse; } }