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
相关产品推荐
相关产品推荐

