board_painter.dart 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:gobang/models/position.dart';
  3. import 'package:gobang/utils/constants.dart';
  4. /// 棋盘 + 棋子绘制;最后一手支持缩放入场与高亮光圈。
  5. class BoardPainter extends CustomPainter {
  6. BoardPainter({
  7. required this.pieces,
  8. required this.version,
  9. this.lastMoveScale = 1,
  10. this.lastMovePulse = 0,
  11. });
  12. final List<Position> pieces;
  13. final int version;
  14. final double lastMoveScale;
  15. final double lastMovePulse;
  16. @override
  17. void paint(Canvas canvas, Size size) {
  18. final cell = size.width / (kBoardSize - 1);
  19. final bg = Paint()
  20. ..isAntiAlias = true
  21. ..style = PaintingStyle.fill
  22. ..color = const Color(0x77cdb175);
  23. canvas.drawRect(Offset.zero & size, bg);
  24. final line = Paint()
  25. ..style = PaintingStyle.stroke
  26. ..color = CupertinoColors.systemGrey6
  27. ..strokeWidth = 1;
  28. for (var i = 0; i < kBoardSize; i++) {
  29. final o = cell * i;
  30. canvas.drawLine(Offset(0, o), Offset(size.width, o), line);
  31. canvas.drawLine(Offset(o, 0), Offset(o, size.height), line);
  32. }
  33. final radius = cell / 2 - 2;
  34. final fill = Paint()..style = PaintingStyle.fill;
  35. final lastIndex = pieces.length - 1;
  36. for (var i = 0; i < pieces.length; i++) {
  37. final p = pieces[i];
  38. final isLast = i == lastIndex;
  39. final center = Offset(p.dx, p.dy);
  40. final scale = isLast ? lastMoveScale.clamp(0.0, 1.2) : 1.0;
  41. final r = radius * scale;
  42. if (isLast && lastMovePulse > 0) {
  43. final ring = Paint()
  44. ..style = PaintingStyle.stroke
  45. ..strokeWidth = 2.5
  46. ..color = const Color(0xE0E53935).withValues(
  47. alpha: 0.85 * lastMovePulse,
  48. );
  49. canvas.drawCircle(center, radius * (1.15 + 0.45 * lastMovePulse), ring);
  50. }
  51. fill.color = p.chess.color;
  52. if (p.chessShape.shape == 1) {
  53. canvas.drawCircle(center, r, fill);
  54. } else {
  55. canvas.drawRect(
  56. Rect.fromCircle(center: center, radius: r),
  57. fill,
  58. );
  59. }
  60. // 最后一手中心小三角标记,方便辨认落点
  61. if (isLast && scale > 0.85) {
  62. final mark = Paint()
  63. ..style = PaintingStyle.fill
  64. ..color = const Color(0xFFE53935);
  65. final s = radius * 0.28;
  66. final path = Path()
  67. ..moveTo(center.dx, center.dy - s)
  68. ..lineTo(center.dx - s * 0.9, center.dy + s * 0.7)
  69. ..lineTo(center.dx + s * 0.9, center.dy + s * 0.7)
  70. ..close();
  71. canvas.drawPath(path, mark);
  72. }
  73. }
  74. }
  75. @override
  76. bool shouldRepaint(covariant BoardPainter oldDelegate) {
  77. return oldDelegate.version != version ||
  78. oldDelegate.lastMoveScale != lastMoveScale ||
  79. oldDelegate.lastMovePulse != lastMovePulse;
  80. }
  81. }