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

Flutter Flame相机无法跟随玩家问题求助

相机无法跟随Flame玩家的解决方案

问题根源

  1. 全局维护玩家位置状态(birdX/birdY)并在update中直接覆盖player.position,外部强制赋值可能导致相机无法正确监听玩家位置变更。
  2. 将camera.follow移到update中重复调用,会创建多个跟随控制器引发冲突报错。

解决方案

将玩家的运动逻辑封装到组件内部,仅在初始化时调用一次相机跟随。

修改后的Player组件

import 'package:flame/components.dart';
import 'package:flutter/material.dart';

class Player extends PositionComponent {
  final VoidCallback collisionCallback;
  double speedY = 0;

  // 可根据需求调整玩家大小
  Player({required Vector2 position, required this.collisionCallback}) 
    : super(position: position, size: Vector2(50, 50));

  void flap() {
    speedY = -5;
  }

  @override
  void update(double dt) {
    // 组件内部处理垂直运动逻辑
    position.y += speedY;
    speedY += 0.1;
    super.update(dt);
  }
}

修改后的MainGame代码

import 'dart:async';
import 'dart:math';
import 'package:flame/events.dart';
import 'package:flame/flame.dart';
import 'package:flame/game.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:whirlybird/components/obstacle.dart';
import 'package:whirlybird/components/player.dart';

class GameScreen extends StatelessWidget {
  const GameScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return GameWidget(
      game: MainGame(),
    );
  }
}

class MainGame extends FlameGame with HorizontalDragDetector, HasCollisionDetection, TapDetector {
  @override
  Color backgroundColor() => Colors.white;

  late double touchDownX;
  late final Player player;

  @override
  bool get debugMode => kDebugMode;

  @override
  void onRemove() {
    Flame.images.clearCache();
    Flame.assets.clearCache();
    super.onRemove();
  }

  @override
  FutureOr<void> onLoad() async {
    // 生成障碍物
    final random = Random();
    for (int i = 0; i < 10; i++) {
      final x = random.nextDouble() * (size[0] - 10) + 10;
      final y = random.nextDouble() * (size[1] - 10) + 10;
      add(Obstacle(positionVector: Vector2(x, y)));
    }

    // 创建并添加玩家
    player = Player(
      position: Vector2(50, 500),
      collisionCallback: flap,
    );
    add(player);

    // 配置相机跟随:以玩家为中心,关闭平滑过渡方便测试
    camera.follow(player, anchor: Anchor.center, maxSpeed: double.infinity);

    return super.onLoad();
  }

  void flap() {
    player.flap();
  }

  @override
  void onHorizontalDragDown(DragDownInfo info) {
    touchDownX = info.raw.globalPosition.dx;
  }

  @override
  void onHorizontalDragUpdate(DragUpdateInfo info) {
    double touchX = info.raw.globalPosition.dx;
    double deltaX = touchX - touchDownX;
    // 直接修改玩家水平位置
    player.position.x += deltaX;
    touchDownX = touchX;
  }

  @override
  void update(double dt) {
    // 玩家垂直运动逻辑已移至组件内部,此处无需额外处理
    super.update(dt);
  }
}

关键修改说明

  • 组件化封装:将玩家的垂直运动、速度状态移到Player组件内部,让组件自行管理位置更新,确保相机能正确监听位置变化。
  • 相机跟随配置:仅在onLoad中调用一次camera.follow,通过anchor: Anchor.center让相机以玩家为中心,maxSpeed: double.infinity关闭平滑跟随(如需平滑效果可改为具体数值,如200)。
  • 移除全局状态:删除全局的birdX/birdY/birdSpeed,直接操作player.position处理水平拖拽,代码结构更符合Flame组件化设计规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:51:21