You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flame升级后调用SetState刷新Overlay引发游戏整体闪烁的解决方案咨询

解决Flame升级后Overlay刷新导致的屏幕闪烁问题

你的问题根源在于每次调用setState()都会重建整个Stack,包括里面的GameWidget——Flame的GameWidget在重建过程中会触发游戏画面的重新渲染,这就导致了300ms一次的闪烁。下面给你两种更优雅的解决思路:

方案一:使用Flame内置的Overlay系统(推荐)

Flame本身提供了游戏内的Overlay机制,完全不需要依赖Flutter的setState来更新UI,这样既能避免Widget树重建,也更符合Flame的游戏架构设计。

修改步骤:

  1. 在你的BoatGame类中创建一个分数Overlay组件:
class ScoreOverlay extends OverlayWidget<BoatGame> {
  ScoreOverlay(BoatGame game) : super(game);

  @override
  Widget build(BuildContext context) {
    return Positioned(
      top: 20,
      left: 20,
      child: Text(
        "My Score: ${game.getScore()}",
        style: TextStyle(color: Colors.white, fontSize: 24),
      ),
    );
  }
}
  1. 在BoatGame的onLoad方法中注册这个Overlay:
class BoatGame extends FlameGame {
  @override
  Future<void> onLoad() async {
    await super.onLoad();
    addOverlay('score', (game) => ScoreOverlay(game));
  }

  // 你的分数逻辑...
  int getScore() => _score;
}
  1. 当分数更新时,直接通知Overlay刷新(不需要外部的setState):
    在游戏内部分数变化的地方,调用:
overlays.refresh('score');

这样只会刷新分数Overlay,不会影响游戏主画面,自然就不会闪烁了。

方案二:用ValueNotifier分离状态(保留Flutter Widget的方式)

如果你更习惯用Flutter的Widget来展示分数,可以用ValueNotifier来管理分数状态,让只有分数文本部分重建,而GameWidget保持稳定。

修改你的代码:

class _Boat extends State<Boat> with WidgetsBindingObserver {
  BoatGame game;
  final ValueNotifier<int> scoreNotifier = ValueNotifier(0);
  Timer? timer;

  @override
  void initState() {
    super.initState();
    game = BoatGame();
    refreshScore();
  }

  refreshScore() async {
    timer = Timer.periodic(const Duration(milliseconds: 300), (timer) {
      if (mounted && game != null) {
        scoreNotifier.value = game.getScore();
      }
    });
  }

  @override
  void dispose() {
    timer?.cancel();
    scoreNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        GameWidget(game: game),
        ValueListenableBuilder<int>(
          valueListenable: scoreNotifier,
          builder: (context, score, child) {
            return Text("My Score: $score");
          },
        ),
      ],
    );
  }
}

这样每次分数更新时,只有ValueListenableBuilder内部的Text会重建,GameWidget不会被重新构建,也就不会出现闪烁了。

另外提醒一下:记得在dispose方法里取消Timer和释放ValueNotifier,避免内存泄漏哦。

内容的提问来源于stack exchange,提问作者PierrickG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 14:48:12