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

Flutter/Dart游戏开发:角色血量实时更新的数据流实现问询

解决方案

一、场景适配判断

你的场景不需要引入Bloc框架,用**简单的StreamController**就能实现需求,轻量且足够解决实时更新血量的问题。

二、具体实现步骤

1. 定义血量更新事件类

先创建一个用于传递更新信息的类,用来告诉UI哪个格子的血量发生了变化:

class HealthUpdate {
  final int row;
  final int col;
  final int newHealth;

  HealthUpdate(this.row, this.col, this.newHealth);
}

2. 在棋盘State类中初始化StreamController

在棋盘页面的State类里,添加StreamController相关代码,用于管理血量更新的流:

class _BoardPageState extends State<BoardPage> {
  // 广播式控制器,支持多个监听者
  final StreamController<HealthUpdate> _healthUpdateController = StreamController<HealthUpdate>.broadcast();
  late List<List<CharacterModel>> board;
  int? selectedRow;
  int? selectedColumn;

  @override
  void dispose() {
    // 页面销毁时关闭控制器,避免内存泄漏
    _healthUpdateController.close();
    super.dispose();
  }

  // 处理双击减血的逻辑
  void damageModel(int row, int col) {
    if (board[row][col].currentHealth > 0) {
      final newHealth = board[row][col].currentHealth - 1;
      board[row][col].currentHealth = newHealth;
      // 发送更新事件到流中,通知UI刷新
      _healthUpdateController.add(HealthUpdate(row, col, newHealth));
    }
  }

  void modelSelected(int row, int col) {
    setState(() {
      selectedRow = row;
      selectedColumn = col;
    });
  }

3. 修改棋盘的Build方法

用StreamBuilder监听流的变化,触发UI更新:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StreamBuilder<HealthUpdate>(
        // 初始数据避免页面加载时显示加载框
        initialData: HealthUpdate(-1, -1, 0),
        stream: _healthUpdateController.stream,
        builder: (context, snapshot) {
          return GridView.builder(
            itemCount: 8 * 8,
            physics: const NeverScrollableScrollPhysics(),
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 8),
            itemBuilder: (context, index) {
              int row = index ~/ 8;
              int col = index % 8;
              bool isSelected = selectedRow == row && selectedColumn == col;
              return Square(
                tile: board[row][col],
                isSelected: isSelected,
                onTap: () => modelSelected(row, col),
                // 传递当前格子的行列信息
                onDoubleTap: () => damageModel(row, col),
              );
            },
          );
        },
      ),
    );
  }
}

4. 修复Square组件的问题

你的Square组件存在变量定义错误,同时无需额外传递currentHealth,直接使用tile内的属性即可:

Widget build(BuildContext context) {
  String selectedImage = tile!.imagePath;

  if (isSelected) {
    selectedImage = './lib/images/dungeon_tile_1.png';
  }

  return GestureDetector(
    onDoubleTap: onDoubleTap,
    onTap: onTap,
    child: Stack(
      children: [
        Container(
          child: tile != null ? Image.asset(selectedImage) : null,
        ),
        // 简化条件判断写法
        if (tile!.currentHealth > 0)
          Align(
            alignment: Alignment.bottomRight,
            child: Padding(
              padding: EdgeInsets.all(10),
              child: Text(
                tile!.currentHealth.toString(),
                style: const TextStyle(
                  color: Colors.red,
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
            ),
          ),
      ],
    ),
  );
}

三、为什么不用Bloc?

Bloc适合复杂状态管理场景(比如多页面共享状态、多层业务逻辑拆分),你的需求只是单个页面内的格子血量更新,用StreamController完全足够,代码更简洁,不需要额外引入依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 03:14:53