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

Flutter Flame Priority值失效求助:组件层级显示异常

Flutter Flame 组件层级优先级问题

我在Flutter Flame开发中创建了Obstacle这个SpriteComponent,父类构造方法里设置了priority值为0。但该组件通过update方法重新生成,移出屏幕后再次出现时,priority值失效,导致Player显示在障碍物后方;同时GameOverPanel始终处于底层,无法正常显示在顶层。


核心游戏类代码

@override
Future<void> onLoad() async {
  add(ScreenHitbox());

  add(gameRef.homeBackgroundParallaxComponent);
  add(gameRef.homeBaseParallax);

  add(gameRef.obstacleManager..priority = 0);
  add(gameRef.playerManager..priority = 1);
  add(gameRef.gameOverPanel..priority = 2);
}

@override
void update(double dt) {
  super.update(dt);
  gameRef.obstacleManager.updateObstacle(GameConst.gameSpeed * dt);
  gameRef.playerManager.changePositionDown(value: GameConst.gravity * dt);
}

GameOverPanel 初始代码

class GameOverPanel extends Component with HasGameRef<HopyBirdGame> {
  GameOverPanel() : super(priority: 4);

  @override
  Future<void> onLoad() async {
    add(GameOverText());
  }

  @override
  void renderTree(Canvas canvas) {
    if (gameRef.gameOver) {
      super.renderTree(canvas);
    }
  }
}

class GameOverText extends SpriteComponent with HasGameRef<HopyBirdGame> {
  GameOverText() : super(size: Vector2(300, 80), anchor: Anchor.center);

  @override
  Future<void>? onLoad() async {
    sprite = await gameRef.loadSprite(Assets.gameOver.path);
    position = Vector2(gameRef.screenWidth / 2, gameRef.screenHeight / 2);
    return super.onLoad();
  }
}

Obstacle 相关代码

Obstacle 类

class Obstacle extends SpriteComponent
    with HasGameRef<HopyBirdGame>, CollisionCallbacks {
  final ObstacleType obstacleType;

  Obstacle({
    required this.obstacleType,
    super.position,
    super.priority,
  }) : super(
          size: Vector2(GameConst.obstacleWidth, GameConst.obstacleHeight),
          anchor: Anchor.center,
        );

  Obstacle.empty({this.obstacleType = ObstacleType.empty});

  @override
  Future<void> onLoad() async {
    switch (obstacleType) {
      case ObstacleType.up:
        sprite = await gameRef.loadSprite(
          Assets.redPipeUp.path,
        );

        break;
      case ObstacleType.down:
        sprite = await gameRef.loadSprite(
          Assets.redPipeDown.path,
        );

        break;

      case ObstacleType.empty:
        return;
    }

    add(RectangleHitbox());
  }
}

Obstacles 容器类

class Obstacles extends Component with HasGameRef<HopyBirdGame> {
  final Obstacle upObstacle;
  final Obstacle downObstacle;
  bool isCreateNextObstacles = true;

  Obstacles({
    required this.upObstacle,
    required this.downObstacle,
    super.priority,
  });

  @override
  Future<void>? onLoad() {
    upObstacle.priority = 1;
    downObstacle.priority = 1;
    createChildren();
    return super.onLoad();
  }

  void createChildren() {
    final children = [upObstacle, downObstacle];
    addAll(children);
  }
}

ObstacleManager 代码

class ObstacleManager extends Component with HasGameRef<HopyBirdGame> {
  ObstacleManager() : super(priority: 1);
  ListQueue<Obstacles> history = ListQueue();

  @override
  Future<void> onLoad() async {
    createObstacles();
  }

  void updateObstacle(double value) {
    if (!gameRef.gameOver) {
      if (history.isNotEmpty) {
        history.last.upObstacle.position.x -= value;
        history.last.downObstacle.position.x -= value;
        if (history.last.upObstacle.position.x <= gameRef.screenWidth / 2) {
          createObstacles();

          final isThereAnyObstaclesOutsideScreen = history.any(
            (element) =>
                element.downObstacle.position.x <= 
                -(GameConst.obstacleWidth / 2),
          );
          if (isThereAnyObstaclesOutsideScreen) {
            final obstaclesOutsideScreen = history
                .lastWhere((element) => element.downObstacle.position.x <= 0);

            obstaclesOutsideScreen.removeFromParent();
            gameRef.remove(obstaclesOutsideScreen);
          }
        }
        if (history.length >= 2) {
          history.elementAt(history.length - 2).upObstacle.position.x -= value;
          history.elementAt(history.length - 2).downObstacle.position.x -= 
              value;
        }
      }
    }
  }

  void createObstacles() {
    final obstaclesGap = 
        gameRef.screenHeight - gameRef.difficulty.spaceForPlayers;
    final gapAboveTheObstacleOnScreen = 
        ((2 * GameConst.obstacleHeight) - obstaclesGap) / 2;

    final randomNumber = _randomGenerator(
      min: -gameRef.difficulty.distanceAxisYToGoUpAndDown,
      max: gameRef.difficulty.distanceAxisYToGoUpAndDown,
    );

    final axisYOfUpObstacle = (GameConst.obstacleHeight / 2) - 
        gapAboveTheObstacleOnScreen + 
        randomNumber;

    final axisYOfDownObstacle = axisYOfUpObstacle + 
        GameConst.obstacleHeight + 
        gameRef.difficulty.spaceForPlayers;

    final obstacles = Obstacles(
      upObstacle: Obstacle(
        obstacleType: ObstacleType.up,
        position: Vector2(
          gameRef.screenWidth + (GameConst.obstacleWidth / 2),
          axisYOfUpObstacle,
        ),
      ),
      downObstacle: Obstacle(
        obstacleType: ObstacleType.down,
        position: Vector2(
          gameRef.screenWidth + (GameConst.obstacleWidth / 2),
          axisYOfDownObstacle,
        ),
      ),
    );

    history.add(obstacles);
    gameRef.add(obstacles);
  }

  double _randomGenerator({required double min, required double max}) {
    final gap = (max - min).toInt();
    return min + Random().nextInt(gap);
  }
}

编辑补充:修改后的 GameOverPanel 代码

class GameOverPanel extends Component with HasGameRef<HopyBirdGame> {
  GameOverPanel() : super();

  @override
  Future<void> onLoad() async {
    add(GameOverText());
  }

  @override
  void renderTree(Canvas canvas) {
    if (gameRef.gameOver) {
      super.renderTree(canvas);
    }
  }
}

class GameOverText extends SpriteComponent with HasGameRef<HopyBirdGame> {
  GameOverText()
      : super(
          size: Vector2(300, 80),
          anchor: Anchor.center,
        );

  @override
  Future<void>? onLoad() async {
    sprite = await gameRef.loadSprite(Assets.gameOver.path);
    position = Vector2(gameRef.screenWidth / 2, gameRef.screenHeight / 2);
    return super.onLoad();
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 13:05:25