如何在Flutter游戏中即时检查全局游戏状态变量值?
解决Flutter游戏中点击操作即时触发状态检查的问题
你当前的问题核心在于:全局变量tapCount更新后,GameState组件没有收到状态变化通知,只有计时器触发setState时才会重新检查胜利条件。以下是两种可行的解决方法:
方法一:通过回调函数触发父组件状态更新
这种方法不需要修改全局变量的定义,通过给子组件添加回调,在点击时主动通知GameState刷新状态:
- 修改
Dot组件,添加点击回调参数
class Dot extends StatefulWidget { final String itemText; final VoidCallback? onTapCallback; // 新增回调参数 const Dot({super.key, required this.itemText, this.onTapCallback}); @override State<Dot> createState() => _DotState(); } class _DotState extends State<Dot> { bool tapped = false; @override Widget build(BuildContext context) { return InkWell( onTap: increaseTap, child: tapped == false ? CircleAvatar( backgroundColor: randomColor(), radius: 10, child: Text(widget.itemText), ) : const SizedBox(width: 20, height: 20), ); } Color randomColor() { return Colors.primaries[Random().nextInt(Colors.primaries.length)]; } void increaseTap() { global.tapCount++; setState(() { tapped = true; }); widget.onTapCallback?.call(); // 点击时触发回调 } }
- 修改
GameGrid组件,传递回调给每个Dot
class GameGrid extends StatelessWidget { final VoidCallback onTapCallback; // 新增回调参数 const GameGrid({super.key, required this.onTapCallback}); @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Dot(itemText: '1', onTapCallback: onTapCallback), Dot(itemText: '2', onTapCallback: onTapCallback), Dot(itemText: '3', onTapCallback: onTapCallback), Dot(itemText: '4', onTapCallback: onTapCallback), ], ), // 其余Row中的Dot都按此方式添加onTapCallback参数 // ...(省略重复代码) ], ); } }
- 在
GameState中使用GameGrid时传入回调
在getScreen方法里,返回GameGrid时传递触发setState的回调:
else if (timer > 0 && gameRunning == true) { return GameGrid(onTapCallback: () { setState(() {}); // 触发状态更新,重新检查胜利条件 }); }
方法二:使用ValueNotifier管理全局状态(更优雅)
通过ValueNotifier可以让全局变量的变化自动通知UI更新,无需手动调用setState:
- 修改
global.dart文件,用ValueNotifier替代普通变量
import 'package:flutter/foundation.dart'; final ValueNotifier<int> tapCount = ValueNotifier(0); final ValueNotifier<int> timer = ValueNotifier(5);
- 修改
Dot组件中的点击逻辑
void increaseTap() { global.tapCount.value++; // 更新ValueNotifier的值 setState(() { tapped = true; }); }
- 修改
GameState组件,监听变量变化
用ValueListenableBuilder包裹页面内容,自动监听tapCount和timer的变化:
@override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Container( color: Colors.black, child: Stack( children: [ ValueListenableBuilder( // 合并多个监听对象,任意一个变化都会触发重建 valueListenable: Listenable.merge([global.tapCount, global.timer]), builder: (context, _, __) { return getScreen( global.timer.value, gameRunning, global.tapCount.value ); }, ), debugWidget(), ], ), )), ); }
- 更新
GameState中的变量操作逻辑
void setGameVarables() { setState(() { global.timer.value = 5; global.tapCount.value = 0; gameRunning = true; timerRunning = true; }); } @override void initState() { Timer.periodic(const Duration(seconds: 1), (Timer time) { if (gameRunning == true && timerRunning == true) { global.timer.value--; // 更新ValueNotifier的值 } }); SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); super.initState(); }
效果说明
两种方法都能实现点击圆点后即时更新tapCount并检查胜利条件,一旦tapCount达到5,会立刻切换到下一级页面。方法一适合简单场景,方法二更适合需要全局状态管理的复杂游戏,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者hefty_kat
相关产品推荐
相关产品推荐

