如何使用Flame库为单词搜索游戏的方格添加蓝色半透明覆盖层
问题原因
你的代码无法达到预期效果主要有三个核心问题:
- 每次触摸方格都会新增一个
Box2覆盖层,同一个位置多次叠加后半透明效果累加,最终变成几乎完全不透明,遮挡下层文字 Box2设置的锚点是Anchor.center,而你直接复用了Box组件的x/y坐标赋值,导致覆盖层和方格位置错位,进一步放大了遮挡问题- 新增的
Box2组件层级始终高于先添加的Box文字组件,文字默认在下层,自然会被上层的覆盖层遮挡
最优解决方案(复杂度最低)
不需要额外新增Box2组件,直接改造原有Box组件的渲染逻辑即可,通过状态控制是否绘制半透明覆盖层:
- 给
Box组件新增isSelected选中状态标记 - 在
Box的渲染逻辑中,先绘制方格背景,选中状态下绘制半透明蓝色覆盖层,最后绘制文字,保证文字永远在最上层不会被遮挡 - 触摸事件中直接修改对应
Box的选中状态即可,不需要新增任何组件
改造后的代码示例
1. 改造Box组件
class Box extends PositionComponent { final String text; // 新增选中状态标记 bool isSelected = false; static const squareSize = 50.0; // 文字绘制工具 final TextPaint _textPainter = TextPaint( style: const TextStyle(color: Colors.black, fontSize: 24, fontWeight: FontWeight.bold), ); Box({ required this.text, Vector2? position, }) : super( size: Vector2.all(squareSize), position: position, // 统一使用topLeft锚点,避免位置计算混乱 anchor: Anchor.topLeft, ); @override void render(Canvas c) { super.render(c); // 1. 绘制方格默认背景 c.drawRect( Rect.fromLTWH(2, 2, size.x - 4, size.y - 4), PaletteEntry(Colors.white).paint(), ); // 2. 选中状态下绘制半透明蓝色覆盖层 if (isSelected) { c.drawRect( Rect.fromLTWH(2, 2, size.x - 4, size.y - 4), PaletteEntry(Colors.blue.withOpacity(0.5)).paint(), ); } // 3. 最后绘制文字,保证文字在最上层 _textPainter.render( c, text, Vector2(size.x/2 - 7, size.y/2 - 12), ); } }
2. 简化触摸事件逻辑
@override void onPanDown(DragDownInfo info) { final touchPos = info.eventPosition.game; // 遍历所有Box组件,选中触摸位置的方格 components.whereType<Box>().forEach((box) { if (box.toRect().contains(touchPos)) { box.isSelected = true; } }); super.onPanDown(info); } @override void onPanUpdate(DragUpdateInfo info) { final touchPos = info.eventPosition.game; components.whereType<Box>().forEach((box) { if (box.toRect().contains(touchPos) && !box.isSelected) { box.isSelected = true; } }); super.onPanUpdate(info); }
如果需要在滑动结束后清除选中状态,只需要在onPanEnd和onPanCancel中遍历所有Box把isSelected设为false即可。
内容的提问来源于stack exchange,提问作者Trần Văn Hiếu
相关产品推荐
相关产品推荐

