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

Flame Engine嵌入Flutter网页时屏幕缩放引发游戏重置的问题求助

我之前在做Flame游戏嵌入Flutter Web时也碰到过一模一样的问题,核心原因其实挺容易忽略的,给你一步步拆解解决思路:

1. 先解决最根本的问题:避免重复创建Game实例

你现在在build方法里直接GameWidget(game: game()),这意味着每次容器宽度变化触发build时,都会新建一个game()实例!新实例自然会重新执行onLoad,玩家位置当然会重置,onGameResize拿到的也是新实例的初始位置。

把gameContainer改成StatefulWidget,在initState里只初始化一次Game实例:

class GameContainer extends StatefulWidget {
  const GameContainer({Key? key, required this.width}) : super(key: key);

  final double width;

  @override
  State<GameContainer> createState() => _GameContainerState();
}

class _GameContainerState extends State<GameContainer> {
  late final MyGame _game; // 替换成你的Game类名

  @override
  void initState() {
    super.initState();
    _game = MyGame(); // 仅在组件初始化时创建一次
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: 100,
      padding: EdgeInsets.symmetric(horizontal: 40, vertical: 10),
      child: GameWidget(game: _game), // 复用同一个Game实例
    );
  }
}

这一步做完,游戏就不会在缩放时重置了,onGameResize调用时玩家的位置也会保留。

2. 配置Viewport实现自适应缩放

接下来要让游戏视口适配容器尺寸,推荐用Flame的FixedResolutionViewport,它能让游戏逻辑用固定的分辨率运行,渲染时自动缩放适配容器大小,完全不用修改游戏内的位置逻辑:

class MyGame extends FlameGame {
  late Player player; // 你的玩家组件

  @override
  Future<void> onLoad() async {
    super.onLoad();
    // 设置游戏逻辑使用的固定分辨率,比如800x100(和你的容器高度匹配)
    camera.viewport = FixedResolutionViewport(const Vector2(800, 100));
    
    // 初始化玩家(示例)
    player = Player(position: Vector2(400, 50));
    add(player);
  }

  @override
  void onGameResize(Vector2 size) {
    super.onGameResize(size);
    // 如果需要让玩家始终在可视区域内,可以调整相机跟随
    camera.followComponent(player, worldBounds: Rect.fromLTWH(0, 0, 800, 100));
  }
}

这样不管容器怎么缩放,游戏内部的逻辑坐标都不变,只是渲染层面做适配,玩家位置自然不会丢失。

3. 额外的状态备份方案(可选)

如果因为特殊场景需要手动保存玩家状态,可以在Game类里维护一个备份变量,比如在update方法里实时保存最新位置:

class MyGame extends FlameGame {
  late Player player;
  Vector2? _lastPlayerPosition;

  @override
  void update(double dt) {
    super.update(dt);
    // 实时备份玩家位置
    _lastPlayerPosition = player.position.clone();
  }

  @override
  void onGameResize(Vector2 size) {
    // 先拿到备份的位置,再执行父类方法
    final savedPosition = _lastPlayerPosition ?? player.position;
    super.onGameResize(size);
    // 恢复玩家位置(如果需要的话)
    player.position = savedPosition;
  }
}

不过这个方案一般用不上,只要保证Game实例唯一,再配合Viewport,问题基本就解决了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 02:09:09