Flame引擎组件添加至World/Game的判定准则与最佳实践
关于Flame中组件添加至World还是Game的选择准则
我发现要让组件跟随Camera,似乎需要将其添加至World。官方文档有提及但解释模糊。按我之前的理解,未添加至World的组件无法渲染,但实际测试中直接调用add()(添加至Game)也能正常显示组件——只是不会跟随Camera;添加至World时则能跟随。
想知道最佳实践是什么:是否应始终将组件添加至World以保证一致性与安全性?还是存在可直接使用add()的场景?核心问题就是:在Flame中添加对象时,依据什么准则决定将其添加至World还是Game?
Camera可跟随对象的代码示例
import 'package:flame/components.dart'; import 'package:flame/game.dart'; import 'package:flutter/material.dart'; void main() { runApp(const FooApp()); } class FooApp extends StatelessWidget { const FooApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: GameWidget.controlled(gameFactory: CameraTrackingExample.new), ); } } class CameraTrackingExample extends FlameGame { late final MyMap map; late final SpriteComponent _appleSpriteComponent; final _speed = 200.0; @override Future<void> onLoad() async { super.onLoad(); map = MyMap(); world.add(map); final appleSprite = await Sprite.load('apple.png'); _appleSpriteComponent = SpriteComponent( position: Vector2(400, 100), size: Vector2(100, 100), sprite: appleSprite, anchor: Anchor.center, ); world.add(_appleSpriteComponent); camera.follow(_appleSpriteComponent); } @override void update(double dt) { super.update(dt); _appleSpriteComponent.position.y += _speed * dt; } } class MyMap extends PositionComponent { MyMap() : super( size: Vector2.all(length), ); static const double length = 1500; @override void render(Canvas canvas) { super.render(canvas); const steps = 10; for (var i = steps; i >= 0; i -= 1) { canvas.drawRect( Rect.fromCenter( center: Offset(width * 0.5, height * 0.5), width: width / steps * i.toDouble(), height: height / steps * i.toDouble(), ), Paint()..color = Color.fromARGB(255, 0, ((200 / steps) * i).toInt(), 0), ); } } }
Camera无法跟随对象的代码示例
import 'package:flame/components.dart'; import 'package:flame/game.dart'; import 'package:flutter/material.dart'; void main() { runApp(const FooApp()); } class FooApp extends StatelessWidget { const FooApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: GameWidget.controlled(gameFactory: CameraTrackingExample.new), ); } } class CameraTrackingExample extends FlameGame { late final MyMap map; late final SpriteComponent _appleSpriteComponent; final _speed = 200.0; @override Future<void> onLoad() async { super.onLoad(); map = MyMap(); add(map); // 👈 移除了world调用 final appleSprite = await Sprite.load('apple.png'); _appleSpriteComponent = SpriteComponent( position: Vector2(400, 100), size: Vector2(100, 100), sprite: appleSprite, anchor: Anchor.center, ); add(_appleSpriteComponent); // 👈 移除了world调用 camera.follow(_appleSpriteComponent); } @override void update(double dt) { super.update(dt); _appleSpriteComponent.position.y += _speed * dt; } } class MyMap extends PositionComponent { MyMap() : super( size: Vector2.all(length), ); static const double length = 1500; @override void render(Canvas canvas) { super.render(canvas); const steps = 10; for (var i = steps; i >= 0; i -= 1) { canvas.drawRect( Rect.fromCenter( center: Offset(width * 0.5, height * 0.5), width: width / steps * i.toDouble(), height: height / steps * i.toDouble(), ), Paint()..color = Color.fromARGB(255, 0, ((200 / steps) * i).toInt(), 0), ); } } }
解答:组件添加至World或Game的选择准则
Flame中FlameGame默认包含两个核心层级,作用完全不同:
- World层级:属于游戏的「世界空间」,Camera的平移、缩放、旋转等所有变换操作只会作用于这个层级内的组件。如果你的组件需要跟随Camera移动(比如游戏角色、地图、场景道具),必须通过
world.add()添加。 - Game根层级:属于「屏幕空间」,直接通过
add()添加的组件不受Camera变换影响,始终以固定位置渲染在屏幕上。这类组件适合做UI元素,比如生命值条、得分面板、菜单按钮等,它们不需要随场景移动,保持在屏幕固定位置显示。
最佳实践
- 所有游戏场景内的实体(角色、敌人、地图、道具等)都添加至World,确保它们能正确响应Camera的各种操作,保持场景逻辑的一致性。
- 所有UI元素(HUD、菜单、提示框等)直接添加至Game根层级,避免被Camera变换干扰,始终稳定显示在屏幕上。
你之前的误解是混淆了「Camera可见」和「受Camera变换影响」:未添加到World的组件依然会被渲染,但它们处于独立的屏幕空间,Camera的跟随操作不会改变它们的渲染位置,所以看起来没有跟随Camera移动。
内容的提问来源于stack exchange,提问作者shingo.nakanishi
相关产品推荐
相关产品推荐

