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

如何在Flame中实现类老虎机的无限列表滚动效果?

Flame 老虎机无限滚动实现方案

1. 封装可复用的 SlotColumn 组件

把单列的滚动、组件管理逻辑封装成独立组件,彻底解决多列重复代码的问题。创建三列只需要实例化三次,传不同位置参数即可。

import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/game.dart';

class SlotColumn extends PositionComponent {
  final List<Sprite> sprites;
  final Vector2 gemSize;
  double scrollSpeed; // 滚动速度(像素/秒),支持动态调整
  final List<GemComponent> _currentGems = [];

  SlotColumn({
    required this.sprites,
    required this.gemSize,
    required this.scrollSpeed,
    required super.position,
  }) : super(size: gemSize);

  @override
  Future<void> onLoad() async {
    super.onLoad();
    // 初始化填充足够宝石,覆盖可视区域+预加载2行避免空白
    _fillColumn();
  }

  void _fillColumn() {
    final neededCount = (game.size.y / gemSize.y).ceil() + 2;
    while (_currentGems.length < neededCount) {
      final randomSprite = sprites[Random().nextInt(sprites.length)];
      final lastGemY = _currentGems.isEmpty ? 0 : _currentGems.last.position.y + gemSize.y;
      final newGem = GemComponent(
        gemSprite: randomSprite,
        gemSize: gemSize,
        gemPosition: Vector2(0, lastGemY),
      );
      _currentGems.add(newGem);
      add(newGem);
    }
  }

  @override
  void update(double dt) {
    super.update(dt);
    // 处理整体滚动偏移
    position.y += scrollSpeed * dt;

    // 移除完全滚出屏幕顶部的组件
    _currentGems.removeWhere((gem) {
      final gemGlobalY = gem.position.y + position.y;
      if (gemGlobalY < -gemSize.y) {
        gem.removeFromParent();
        return true;
      }
      return false;
    });

    // 补充新组件到列底部,保持无限滚动
    _fillColumn();
  }
}

// 假设你的GemComponent实现如下(可根据实际调整)
class GemComponent extends SpriteComponent {
  GemComponent({
    required Sprite gemSprite,
    required Vector2 gemSize,
    required Vector2 gemPosition,
  }) : super(
          sprite: gemSprite,
          size: gemSize,
          position: gemPosition,
        );
}

2. 在游戏类中快速创建多列

现在创建三列只需要几行代码,完全不需要重复逻辑:

class SlotMachineGame extends FlameGame {
  late List<Sprite> _sprites;
  final Vector2 gemSize = Vector2(100, 100);
  final double baseScrollSpeed = 250;

  @override
  Future<void> onLoad() async {
    super.onLoad();
    // 加载宝石精灵资源
    _sprites = await Future.wait([
      Sprite.load('gem_red.png'),
      Sprite.load('gem_blue.png'),
      Sprite.load('gem_green.png'),
    ]);

    // 创建三列,设置不同x轴位置
    add(SlotColumn(
      sprites: _sprites,
      gemSize: gemSize,
      scrollSpeed: baseScrollSpeed,
      position: Vector2(60, 0),
    ));
    add(SlotColumn(
      sprites: _sprites,
      gemSize: gemSize,
      scrollSpeed: baseScrollSpeed,
      position: Vector2(220, 0),
    ));
    add(SlotColumn(
      sprites: _sprites,
      gemSize: gemSize,
      scrollSpeed: baseScrollSpeed,
      position: Vector2(380, 0),
    ));
  }
}

关键逻辑说明

  • 复用性:SlotColumn封装了单列所有核心逻辑,多列仅需传递不同位置参数,彻底消除重复代码。
  • 替代MoveEffect:放弃MoveEffect改用update方法手动控制滚动,不仅能灵活调整速度,还能同步处理组件的增删,更适合无限滚动场景。
  • 无限滚动核心:_fillColumn自动判断组件数量,不足时补充新宝石;update中移除出界组件,保持列的持续填充。
  • 扩展性:如果需要实现老虎机拉杆后的减速停止效果,只需给SlotColumn添加targetSpeed变量,在update中逐步把scrollSpeed过渡到0即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 23:05:36