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

Flutter Flame转盘平滑旋转与定时精准停止的实现难题

Flutter转盘平滑旋转与精准停止优化问题

我在Flutter应用中实现了转盘功能,目标是让转盘平滑旋转并在指定时长内精准停在预设位置,但目前无法确保转盘在规定时间内准确停在目标切片上。

具体问题如下:

  • 平滑旋转:难以保持旋转过程中角速度稳定及减速平滑;
  • 精准停止:虽设置了最大速度检测、角度校验等停止条件,但停止位置常超出目标或耗时过长。

以下是当前用于转盘旋转与停止逻辑的代码片段:

class WheelUpdater extends PositionComponent {
  final SpinTheWheel spinTheWheelModel;
  final VoidCallback onSpinStop;

  late double _angularVelocity;
  late bool _spinning;
  late bool _isMaxSpeedReached;
  late int _sliceCount;
  late double _sliceAngle;
  late AudioService _audioService;
  late double _elapsedTime;
  late double stopAngle;
  late int totalDuration;

  WheelUpdater({
    required this.spinTheWheelModel,
    required this.onSpinStop,
  })  : assert(
            spinTheWheelModel.stopPosition <= spinTheWheelModel.slices.length,
            'Stop position must be less than or equal to the number of slices'),
        assert(spinTheWheelModel.duration >= 0,
            'duration must be greater than or equal to 0') {
    _sliceCount = spinTheWheelModel.slices.length;
    _sliceAngle = 2 * pi / _sliceCount;
    _angularVelocity = 0;
    _spinning = false;
    _isMaxSpeedReached = false;
    _audioService = AudioServiceImp();
    totalDuration = spinTheWheelModel.duration;
    _elapsedTime = 0;
  }

  @override
  FutureOr<void> onLoad() async {
    await _audioService.loadAll([Song.tick, Song.winner]);
    return super.onLoad();
  }

  @override
  void onRemove() async {
    await _audioService.clearAll();
    super.onRemove();
  }

  @override
  void update(double dt) {
    super.update(dt);

    double previousAngle = angle;

    if (_spinning) {
      _elapsedTime += dt * 1000;

      angle += _angularVelocity * dt;

      double maxSpeedTime = totalDuration * 0.5;

      if (_elapsedTime >= maxSpeedTime && !_isMaxSpeedReached) {
        _isMaxSpeedReached = true;
      }

      if (_isMaxSpeedReached && _angularVelocity >= 1) {
        _angularVelocity -= dt;
      } else {
        _angularVelocity += dt;
      }

      if (angle >= 2 * pi) {
        angle = (2 * pi) - angle;
      }

      int previousSliceIndex = (previousAngle / _sliceAngle).floor();
      int currentSliceIndex = (angle / _sliceAngle).floor();
      if (previousSliceIndex != currentSliceIndex) {
        _playTickSound();
      }
      if (isStoppingConditionReached) {
        _spinning = false;
        angle = stopAngle + 0.3;
        _winnerDeclared();
        onSpinStop();
      }
    }
  }

  void startSpin() {
    if (!_spinning) {
      _spinning = true;
      _angularVelocity = 0;
      _isMaxSpeedReached = false;
      _elapsedTime = 0;
    }
  }

  bool get isStoppingConditionReached {
    if (spinTheWheelModel.stopPosition == 0) {
      stopAngle = 0;
    } else {
      stopAngle = _sliceAngle * (_sliceCount - spinTheWheelModel.stopPosition);
    }

    double offsetAngle = _sliceAngle * 0.4;
    return _isMaxSpeedReached &&
        _angularVelocity <= 1 &&
        angle >= (stopAngle + offsetAngle) &&
        angle <= (stopAngle + _sliceAngle - offsetAngle);
  }

  /// Plays the tick sound when the wheel rotates to a new slice.
  Future<void> _playTickSound() async {
    await _audioService.play(Song.tick);
  }

  Future<void> _winnerDeclared() async {
    if (spinTheWheelModel.showHapticFeedback) {
      await HapticFeedback.vibrate();
    }

    /// Plays the winner sound when the spinning stops at the designated position.
    await _audioService.play(Song.winner);
  }
}

我已尝试调整角速度、停止条件等参数,但仍未达到预期效果。恳请协助优化逻辑或提供合适公式,以实现转盘的平滑旋转与定时精准停止,感谢您的指导!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:40:13